From 98c43e9d959422e4fa096cbfc7bbfb4886229d44 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 1 Mar 2021 22:53:22 +1100 Subject: [PATCH 01/32] 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 8c2e1c4cab90599453f252c25ff4c6b19a3ed4d6 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 2 Mar 2021 15:24:23 +1100 Subject: [PATCH 02/32] 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 0c113b568accb574c9c7042317fa4cde49c08b4e Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 2 Mar 2021 16:06:45 +1100 Subject: [PATCH 03/32] 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 b98ffe5d8d88a07bd0fcfcc14a7fac10bd05360c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 3 Mar 2021 09:21:40 +1100 Subject: [PATCH 04/32] 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 1e7148a5ffd3333d09648bb25ccdf9af1082a0ba Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 3 Mar 2021 23:22:16 +1100 Subject: [PATCH 05/32] 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 d8c204039b25d4e36eaed957673b9bdb0dca42cb Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 7 Mar 2021 14:36:11 +1100 Subject: [PATCH 06/32] 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 149d4c3f33a03231a826244308dcbb045f8e6817 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 7 Mar 2021 18:27:55 +1100 Subject: [PATCH 07/32] 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 595feeee53a950f886a6e9f8c543ff1a85ac5f5b Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 11 Mar 2021 07:20:28 +1100 Subject: [PATCH 08/32] 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 02b3e79f090d0dfbb31d63a306dbdeab161ef84f Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 11 Mar 2021 12:13:02 +1100 Subject: [PATCH 09/32] 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 c1e264a06bc526565521bbb87c99e7537a0c9d34 Mon Sep 17 00:00:00 2001 From: Nezumi Ronin Date: Wed, 17 Mar 2021 10:31:39 -0600 Subject: [PATCH 10/32] Create hi-lo.pl Made with Perl! --- 47 Hi-Lo/perl/hi-lo.pl | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 47 Hi-Lo/perl/hi-lo.pl diff --git a/47 Hi-Lo/perl/hi-lo.pl b/47 Hi-Lo/perl/hi-lo.pl new file mode 100644 index 00000000..08173a56 --- /dev/null +++ b/47 Hi-Lo/perl/hi-lo.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +use strict; + + +print ' 'x 34 . "HI LO\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +print "THIS IS THE GAME OF HI LO.\n"; print "\n"; +print "YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n"; +print "HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU\n"; +print "GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n"; +print "THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,\n"; +print "IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n"; print "\n"; +my $R=0; +my $A; +do { + print "\n"; + my $Y=int(100*rand(1)); + foreach (1..6) { + print "YOUR GUESS $Y"; + print "? "; chomp($A = ); + if ($A eq $Y) { last; } + if ($A>$Y) { + print "YOUR GUESS IS TOO HIGH.\n"; + } else { + print "YOUR GUESS IS TOO LOW.\n"; + } + print "\n"; + } + + if ($A==$Y) { + $R=$R+$Y; + print "GOT IT!!!!!!!!!! YOU WIN $Y DOLLARS.\n"; + print "YOUR TOTAL WINNINGS ARE NOW $R DOLLARS.\n"; + } else { + $R=0; + print "YOU BLEW IT...TOO BAD...THE NUMBER WAS $Y" + } + print "\n"; print "PLAY AGAIN (YES OR NO)"; + print "? "; chomp($A = ); + } until (uc($A) ne "YES"); +print "\n"; print "SO LONG. HOPE YOU ENJOYED YOURSELF!!!\n"; +exit; + + From 5b1fdfbde16bfc532956255372a75e6734572349 Mon Sep 17 00:00:00 2001 From: Nezumi Ronin Date: Wed, 17 Mar 2021 11:44:37 -0600 Subject: [PATCH 11/32] Create dice.pl Made with Perl! --- 33 Dice/perl/dice.pl | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 33 Dice/perl/dice.pl diff --git a/33 Dice/perl/dice.pl b/33 Dice/perl/dice.pl new file mode 100644 index 00000000..cb051b0a --- /dev/null +++ b/33 Dice/perl/dice.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +use strict; + + +print ' 'x 34 . "DICE\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n\n\n"; +my @F; + +#REM DANNY FREIDUS; +print "THIS PROGRAM SIMULATES THE ROLLING OF A\n"; +print "PAIR OF DICE.\n"; +print "YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n"; +print "'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE\n"; +print "A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.\n"; + +my $X; +my $Z; +do { + for (my $Q=1; $Q<=12; $Q++) { + $F[$Q]=0; + } + print "\n"; print "HOW MANY ROLLS"; + print "? "; chomp($X = ); + for (my $S=1; $S<=$X; $S++) { + my $A=int(6*rand(1)+1); + my $B=int(6*rand(1)+1); + my $R=$A+$B; + $F[$R]=$F[$R]+1; + } + print "\n"; + print "TOTAL SPOTS\tNUMBER OF TIMES\n"; + for (my $V=2; $V<=12; $V++) { + print "$V\t\t$F[$V]\n"; + } + print "\n"; + print "\n"; print "TRY AGAIN"; + print "? "; chomp($Z = ); + } until (uc($Z) ne "YES"); +exit; + + From 1f8f230cfc31857910b138f2557e114e6cb24438 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Sat, 20 Mar 2021 16:21:42 +0400 Subject: [PATCH 12/32] Ported 95 Weekday to Java --- 95 Weekday/java/Weekday.java | 280 +++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 95 Weekday/java/Weekday.java diff --git a/95 Weekday/java/Weekday.java b/95 Weekday/java/Weekday.java new file mode 100644 index 00000000..9ca3db11 --- /dev/null +++ b/95 Weekday/java/Weekday.java @@ -0,0 +1,280 @@ +import java.util.Scanner; + +/** + * WEEKDAY + * + * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + * + */ +public class Weekday { + + //TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS. + //Dummy value added at index 0, so we can reference directly by the month number value + private final static int[] t = new int[]{-1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; + + public static void main(String[] args) { + printIntro(); + + Scanner scanner = new Scanner(System.in); + System.out.print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 "); + DateStruct todaysDate = readDate(scanner); + + System.out.print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) "); + DateStruct dateOfInterest = readDate(scanner); + + int I1 = (dateOfInterest.year - 1500) / 100; + //TEST FOR DATE BEFORE CURRENT CALENDAR. + if ((dateOfInterest.year - 1582) >= 0) { + int A = I1 * 5 + (I1 + 3) / 4; + int I2 = (A - b(A) * 7); + int Y2 = (dateOfInterest.year / 100); + int Y3 = (dateOfInterest.year - Y2 * 100); + A = Y3 / 4 + Y3 + dateOfInterest.day + t[dateOfInterest.month] + I2; + calculateAndPrintDayOfWeek(I1, A, todaysDate, dateOfInterest, Y3); + + if ((todaysDate.year * 12 + todaysDate.month) * 31 + todaysDate.day + == (dateOfInterest.year * 12 + dateOfInterest.month) * 31 + dateOfInterest.day) { + return; //stop the program + } + + int I5 = todaysDate.year - dateOfInterest.year; + System.out.print("\n"); + int I6 = todaysDate.month - dateOfInterest.month; + int I7 = todaysDate.day - dateOfInterest.day; + if (I7 < 0) { + I6 = I6 - 1; + I7 = I7 + 30; + } + if (I6 < 0) { + I5 = I5 - 1; + I6 = I6 + 12; + } + if (I5 < 0) { + return; //do nothing. end the program + } else { + if (I7 != 0) { + printHeadersAndAge(I5, I6, I7); + } else { + if (I6 != 0) { + printHeadersAndAge(I5, I6, I7); + } else { + System.out.println("***HAPPY BIRTHDAY***"); + printHeadersAndAge(I5, I6, I7); + } + } + } + + int A8 = (I5 * 365) + (I6 * 30) + I7 + (I6 / 2); + int K5 = I5; + int K6 = I6; + int K7 = I7; + //CALCULATE RETIREMENT DATE. + int E = dateOfInterest.year + 65; + // CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS. + float F = 0.35f; + System.out.printf("%-28s", "YOU HAVE SLEPT"); + DateStruct scratchDate = new DateStruct(K6, K7, K5); //K5 is a temp year, K6 is month, K7 is day + printStatisticRow(F, A8, scratchDate); + K5 = scratchDate.year; + K6 = scratchDate.month; + K7 = scratchDate.day; + + F = 0.17f; + System.out.printf("%-28s", "YOU HAVE EATEN"); + + scratchDate = new DateStruct(K6, K7, K5); + printStatisticRow(F, A8, scratchDate); + K5 = scratchDate.year; + K6 = scratchDate.month; + K7 = scratchDate.day; + + F = 0.23f; + if (K5 > 3) { + if (K5 > 9) { + System.out.printf("%-28s", "YOU HAVE WORKED/PLAYED"); + } else { + System.out.printf("%-28s", "YOU HAVE PLAYED/STUDIED"); + } + } else { + System.out.printf("%-28s", "YOU HAVE PLAYED"); + } + + scratchDate = new DateStruct(K6, K7, K5); + printStatisticRow(F, A8, scratchDate); + K5 = scratchDate.year; + K6 = scratchDate.month; + K7 = scratchDate.day; + + if (K6 == 12) { + K5 = K5 + 1; + K6 = 0; + } + System.out.printf("%-28s%14s%14s%14s%n", "YOU HAVE RELAXED", K5, K6, K7); + System.out.printf("%16s*** YOU MAY RETIRE IN %s ***%n", " ", E); + System.out.printf("%n%n%n%n%n"); + } else { + System.out.println("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII."); + } + } + + + private static void printStatisticRow(float F, int A8, DateStruct scratchDate) { + int K1 = (int) (F * A8); + int I5 = K1 / 365; + K1 = K1 - (I5 * 365); + int I6 = K1 / 30; + int I7 = K1 - (I6 * 30); + int K5 = scratchDate.year - I5; + int K6 = scratchDate.month - I6; + int K7 = scratchDate.day - I7; + if (K7 < 0) { + K7 = K7 + 30; + K6 = K6 - 1; + } + if (K6 <= 0) { + K6 = K6 + 12; + K5 = K5 - 1; + } + //to return the updated values of K5, K6, K7 we send them through the scratchDate + scratchDate.year = K5; + scratchDate.month = K6; + scratchDate.day = K7; + System.out.printf("%14s%14s%14s%n", I5, I6, I7); + } + + private static void printHeadersAndAge(int I5, int I6, int I7) { + System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "YEARS", "MONTHS", "DAYS"); + System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "-----", "------", "----"); + System.out.printf("%-28s%14s%14s%14s%n", "YOUR AGE (IF BIRTHDATE)", I5, I6, I7); + } + + private static void calculateAndPrintDayOfWeek(int i1, int a, DateStruct dateStruct, DateStruct dateOfInterest, int y3) { + int b = (a - b(a) * 7) + 1; + if (dateOfInterest.month > 2) { + printDayOfWeek(dateStruct, dateOfInterest, b); + } else { + if (y3 == 0) { + int aa = i1 - 1; + int t1 = aa - a(aa) * 4; + if (t1 == 0) { + if (b != 0) { + b = b - 1; + printDayOfWeek(dateStruct, dateOfInterest, b); + } else { + b = 6; + b = b - 1; + printDayOfWeek(dateStruct, dateOfInterest, b); + } + } + } + } + } + + /** + * PRINT THE DAY OF THE WEEK THE DATE FALLS ON. + */ + private static void printDayOfWeek(DateStruct dateStruct, DateStruct dateOfInterest, int b) { + if (b == 0) { + b = 7; + } + if ((dateStruct.year * 12 + dateStruct.month) * 31 + + dateStruct.day + < + (dateOfInterest.year * 12 + + dateOfInterest.month) * 31 + dateOfInterest.day) { + System.out.printf("%s / %s / %s WILL BE A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year); + } else if ((dateStruct.year * 12 + dateStruct.month) * 31 + + dateStruct.day == (dateOfInterest.year * 12 + dateOfInterest.month) + * 31 + dateOfInterest.day) { + System.out.printf("%s / %s / %s IS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year); + } else { + System.out.printf("%s / %s / %s WAS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year); + } + switch (b) { + case 1: + System.out.println("SUNDAY."); + break; + case 2: + System.out.println("MONDAY."); + break; + case 3: + System.out.println("TUESDAY."); + break; + case 4: + System.out.println("WEDNESDAY."); + break; + case 5: + System.out.println("THURSDAY."); + break; + case 6: + if (dateOfInterest.day == 13) { + System.out.println("FRIDAY THE THIRTEENTH---BEWARE!"); + } else { + System.out.println("FRIDAY."); + } + break; + case 7: + System.out.println("SATURDAY."); + break; + } + } + + private static int a(int a) { + return a / 4; + } + + private static int b(int a) { + return a / 7; + } + + + private static void printIntro() { + System.out.println(" WEEKDAY"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n\n"); + System.out.println("WEEKDAY IS A COMPUTER DEMONSTRATION THAT"); + System.out.println("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU."); + System.out.println("\n"); + } + + /** + * Read user input for a date, do some validation and return a simple date structure + */ + private static DateStruct readDate(Scanner scanner) { + boolean done = false; + int mm = 0, dd = 0, yyyy = 0; + while (!done) { + String input = scanner.next(); + String[] tokens = input.split(","); + if (tokens.length < 3) { + System.out.println("DATE EXPECTED IN FORM: 3,24,1979 - RETRY INPUT LINE"); + } else { + try { + mm = Integer.parseInt(tokens[0]); + dd = Integer.parseInt(tokens[1]); + yyyy = Integer.parseInt(tokens[2]); + done = true; + } catch (NumberFormatException nfe) { + System.out.println("NUMBER EXPECTED - RETRY INPUT LINE"); + } + } + } + return new DateStruct(mm, dd, yyyy); + } + + /** + * Convenience date structure to hold user date input + */ + private static class DateStruct { + int month; + int day; + int year; + + public DateStruct(int month, int day, int year) { + this.month = month; + this.day = day; + this.year = year; + } + } + +} From 6156b233f0cf5639260c19e92179c693ef23deeb Mon Sep 17 00:00:00 2001 From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com> Date: Sat, 20 Mar 2021 12:00:27 -0400 Subject: [PATCH 13/32] Ported Diamond to Java. --- 32 Diamond/java/Diamond.java | 163 +++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 32 Diamond/java/Diamond.java diff --git a/32 Diamond/java/Diamond.java b/32 Diamond/java/Diamond.java new file mode 100644 index 00000000..bbad33a7 --- /dev/null +++ b/32 Diamond/java/Diamond.java @@ -0,0 +1,163 @@ +import java.util.Scanner; + +/** + * Game of Diamond + *

+ * Based on the BASIC game of Diamond here + * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class Diamond { + + private static final int LINE_WIDTH = 60; + + private static final String PREFIX = "CC"; + + private static final char SYMBOL = '!'; + + private final Scanner scan; // For user input + + + public Diamond() { + + scan = new Scanner(System.in); + + } // End of constructor Diamond + + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + + private void showIntro() { + + System.out.println(" ".repeat(32) + "DIAMOND"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + + private void startGame() { + + int body = 0; + int column = 0; + int end = 0; + int fill = 0; + int increment = 2; + int numPerSide = 0; + int prefixIndex = 0; + int row = 0; + int start = 1; + int userNum = 0; + + String lineContent = ""; + + // Get user input + System.out.println("FOR A PRETTY DIAMOND PATTERN,"); + System.out.print("TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? "); + userNum = scan.nextInt(); + System.out.println(""); + + // Calcuate number of diamonds to be drawn on each side of screen + numPerSide = (int) (LINE_WIDTH / userNum); + + end = userNum; + + // Begin loop through each row of diamonds + for (row = 1; row <= numPerSide; row++) { + + // Begin loop through top and bottom halves of each diamond + for (body = start; increment < 0 ? body >= end : body <= end; body += increment) { + + lineContent = ""; + + // Add whitespace + while (lineContent.length() < ((userNum - body) / 2)) { + lineContent += " "; + } + + // Begin loop through each column of diamonds + for (column = 1; column <= numPerSide; column++) { + + prefixIndex = 1; + + // Begin loop that fills each diamond with characters + for (fill = 1; fill <= body; fill++) { + + // Right side of diamond + if (prefixIndex > PREFIX.length()) { + + lineContent += SYMBOL; + + } + // Left side of diamond + else { + + lineContent += PREFIX.charAt(prefixIndex - 1); + prefixIndex++; + + } + + } // End loop that fills each diamond with characters + + // Column finished + if (column == numPerSide) { + + break; + + } + // Column not finishd + else { + + // Add whitespace + while (lineContent.length() < (userNum * column + (userNum - body) / 2)) { + lineContent += " "; + } + + } + + } // End loop through each column of diamonds + + System.out.println(lineContent); + + } // End loop through top and bottom half of each diamond + + if (start != 1) { + + start = 1; + end = userNum; + increment = 2; + + } + else { + + start = userNum - 2; + end = 1; + increment = -2; + row--; + + } + + } // End loop through each row of diamonds + + } // End of method startGame + + + public static void main(String[] args) { + + Diamond diamond = new Diamond(); + diamond.play(); + + } // End of method main + +} // End of class Diamond \ No newline at end of file From 87c8f703544b974f52b63d23902054b0088e8fa9 Mon Sep 17 00:00:00 2001 From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com> Date: Sat, 20 Mar 2021 12:03:19 -0400 Subject: [PATCH 14/32] Add newline to end of Diamond.java. --- 32 Diamond/java/Diamond.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/32 Diamond/java/Diamond.java b/32 Diamond/java/Diamond.java index bbad33a7..da56efe4 100644 --- a/32 Diamond/java/Diamond.java +++ b/32 Diamond/java/Diamond.java @@ -160,4 +160,4 @@ public class Diamond { } // End of method main -} // End of class Diamond \ No newline at end of file +} // End of class Diamond From b5721f6c454d1cccbaf932f95d3ca9c680983107 Mon Sep 17 00:00:00 2001 From: Mark Yocom Date: Sat, 20 Mar 2021 12:06:29 -0700 Subject: [PATCH 15/32] Adding Perl version of aceyducey --- 01 Acey Ducey/perl/aceyducey.pl | 171 ++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 01 Acey Ducey/perl/aceyducey.pl diff --git a/01 Acey Ducey/perl/aceyducey.pl b/01 Acey Ducey/perl/aceyducey.pl new file mode 100644 index 00000000..b193219e --- /dev/null +++ b/01 Acey Ducey/perl/aceyducey.pl @@ -0,0 +1,171 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use List::Util qw(shuffle first); + +# Rather than put in a number of print (or say) statements here, we use a +# "here document". This is very useful for long strings of text. In this +# case, everything between the end of the "print" line and the line with +# "END_INSTRUCTIONS" on it will be printed verbatim. +print << 'END_INSTRUCTIONS'; + +Acey-Ducey +Adapted from Creative Computing, Morristown, New Jersey + + +Acey-Ducey is played as follows. The dealer (computer) deals two cards face up. +You have an option to bet or not bet, depending on whether or not you feel that +the next card drawn will have a value between the first two. Aces are low. + +Bets must be in whole-dollar amounts only. + +If you do not want to bet, input a 0. If you want to quit, input a -1. + +END_INSTRUCTIONS + +my @cards = (1 .. 13); # That is, ace through king. +my $keepPlaying = 1; + +GAME: +while ($keepPlaying) +{ + my $playerBalance = 100; # The player starts with $100 + + HAND: + while (1) + { + print "\nYou now have $playerBalance dollars.\n\n"; + + # We'll create a new array that is a shuffled version of the deck. + my @shuffledDeck = shuffle(@cards); + + # Then, by taking the two "top cards" off the deck, we're guaranteed + # that those will be unique. This way we don't have to keep drawing + # if we get, say, two queens. We sort them as we pull them to make + # sure that the first card is lower than the second one. + my ($firstCard, $secondCard) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ]; + + print "I drew ", nameOfCard($firstCard), " and ", nameOfCard($secondCard), ".\n"; + + my $bet = getValidBet($playerBalance); + if ($bet == 0) + { + print "Chicken!\n\n"; + next HAND; + } + + if ($bet < 0) + { + last GAME; + } + + # Now we re-shuffle the whole deck again and choose a third card. + # (Note: This is how the odds get stacked in favor of the dealer since + # the third card can be exactly the same as the first or second.) + @shuffledDeck = shuffle(@cards); + my $thirdCard = $shuffledDeck[0]; + + print "I drew ", nameOfCard($thirdCard), "!\n"; + + if (($firstCard < $thirdCard) && ($thirdCard < $secondCard)) + { + print "You win!\n\n"; + $playerBalance += $bet; + } + else + { + print "You lose!\n\n"; + $playerBalance -= $bet; + } + + if ($playerBalance <= 0) + { + print "Sorry, buddy, you blew your wad!\n\n"; + last HAND; + } + } + + $keepPlaying = promptUserToKeepPlaying(); +} + +print "Thanks for playing!\n"; + +############### +sub getValidBet +{ + my $maxBet = shift; + + print "\nWhat's your bet? "; + + my $input = ; + chomp $input; + + # This regular expression will validate that the player entered an integer. + # The !~ match operate *negates* the match, so if the player did NOT enter + # an integer, they'll be given an error and prompted again. + if ($input !~ /^ # Match the beginning of the string + [+-]? # Optional plus or minus... + \d+ # followed by one more more digits... + $ # and then the end of the string + /x # The x modifier ignores whitespace in this regex... + ) + { + print "Sorry, numbers only!\n"; + $input = getValidBet($maxBet); + } + + if ($input > $maxBet) + { + print "Sorry, my friend, you can't bet more money than you have.\n"; + print "You only have $maxBet dollars to spend!\n"; + $input = getValidBet($maxBet); + } + + if ($input != int($input)) + { + print "Sorry, you must bet in whole dollars. No change!\n"; + $input = getValidBet($maxBet); + } + + return $input; +} + +# Since arrays in Perl are 0-based, we need to convert the value that we drew from +# the array to its proper position in the deck. +sub nameOfCard +{ + my $value = shift; + + # Note that the Joker isn't used in this game, but since arrays in Perl are + # 0-based, it's useful to have something there to represent the "0th" + # position. This way the rest of the elements match their expected values + # (e.g., element 1 is Ace, element 7 is 7, and element 12 is Queen). + + my @cardlist = qw(Joker Ace 2 3 4 5 6 7 8 9 10 Jack Queen King); + return $cardlist[$value]; +} + +sub promptUserToKeepPlaying +{ + print "Try again (Y/N)? "; + my $input = ; + chomp $input; + + my $keepGoing; + if (uc($input) eq 'Y') + { + $keepGoing = 1; + } + elsif (uc($input) eq 'N') + { + $keepGoing = 0; + } + else + { + $keepGoing = promptUserToKeepPlaying(); + } + + return $keepGoing; +} From 774ec9303e27978d04e85904aa705e9e177865af Mon Sep 17 00:00:00 2001 From: Mark Yocom Date: Sat, 20 Mar 2021 12:11:11 -0700 Subject: [PATCH 16/32] Removing unused first() from List::Util import --- 01 Acey Ducey/perl/aceyducey.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/01 Acey Ducey/perl/aceyducey.pl b/01 Acey Ducey/perl/aceyducey.pl index b193219e..e2de13df 100644 --- a/01 Acey Ducey/perl/aceyducey.pl +++ b/01 Acey Ducey/perl/aceyducey.pl @@ -3,7 +3,10 @@ use strict; use warnings; -use List::Util qw(shuffle first); +# The List::Util module is part of the core Perl distribution. Using this +# means we don't need to re-invent the wheel and create a way to shuffle +# a list. +use List::Util qw(shuffle); # Rather than put in a number of print (or say) statements here, we use a # "here document". This is very useful for long strings of text. In this @@ -25,7 +28,7 @@ If you do not want to bet, input a 0. If you want to quit, input a -1. END_INSTRUCTIONS -my @cards = (1 .. 13); # That is, ace through king. +my @cards = (1 .. 13); # That is, Ace through King. my $keepPlaying = 1; GAME: From 49c5429c3246a1a5705cf303842bd590cc901401 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:39:19 +1100 Subject: [PATCH 17/32] 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 6d88bccef6d98256418fc369b46f71606601ebdc Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:46:32 +1100 Subject: [PATCH 18/32] 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 2e58c3b7051e9664f99c609f865866ab53f3f211 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:54:14 +1100 Subject: [PATCH 19/32] 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 3f0230e2167056ff84de478a89da49791a8dc130 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:00:54 +1100 Subject: [PATCH 20/32] 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 25c948d6cbc92b8a6f661421b4f59bdaee0bedbe Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:12:44 +1100 Subject: [PATCH 21/32] 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 3e8e9364d993866ec6c6486561f3239b17792acf Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 13:55:55 +1100 Subject: [PATCH 22/32] 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"); From db3ccc19cc754acb3cbe6bcc6bf2225898e6d5a1 Mon Sep 17 00:00:00 2001 From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com> Date: Sun, 21 Mar 2021 11:38:43 -0400 Subject: [PATCH 23/32] Ported 3-D Plot to Java. --- 87 3-D Plot/java/Plot3D.java | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 87 3-D Plot/java/Plot3D.java diff --git a/87 3-D Plot/java/Plot3D.java b/87 3-D Plot/java/Plot3D.java new file mode 100644 index 00000000..77ffbb8d --- /dev/null +++ b/87 3-D Plot/java/Plot3D.java @@ -0,0 +1,97 @@ +import java.lang.Math; + +/** + * Game of 3-D Plot + *

+ * Based on the BASIC game of 3-D Plot here + * https://github.com/coding-horror/basic-computer-games/blob/main/87%203-D%20Plot/3dplot.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +// Java class names cannot begin with a letter, so class name 3dplot cannot be used +public class Plot3D { + + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + + private void showIntro() { + + System.out.println(" ".repeat(31) + "3D PLOT"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n\n"); + + } // End of method showIntro + + + private void startGame() { + + float row = 0; + int column = 0; + int limit = 0; + int plotVal = 0; + int root = 0; + + String lineContent = ""; + + // Begin loop through all rows + for (row = -30; row <= 30; row += 1.5) { + + limit = 0; + + root = 5 * (int) Math.floor((Math.sqrt(900 - row * row) / 5)); + + // Begin loop through all columns + for (column = root; column >= -root; column += -5) { + + plotVal = 25 + (int) Math.floor(func(Math.sqrt(row * row + column * column)) - 0.7 * column); + + if (plotVal > limit) { + + limit = plotVal; + + // Add whitespace + while (lineContent.length() < (plotVal-1)) { + lineContent += " "; + } + + lineContent += "*"; + + } + + } // End loop through all columns + + System.out.println(lineContent); + + lineContent = ""; + + } // End loop through all rows + + } // End of method startGame + + + // Function to be plotted + public double func(double inputVal) { + + return (30 * Math.exp(-inputVal * inputVal / 100)); + + } + + + public static void main(String[] args) { + + Plot3D plot = new Plot3D(); + plot.play(); + + } // End of method main + +} // End of class Plot3D \ No newline at end of file From 63ce61dcbfb468229295b78a9b923d453682d982 Mon Sep 17 00:00:00 2001 From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com> Date: Sun, 21 Mar 2021 11:40:29 -0400 Subject: [PATCH 24/32] Add newline to end of Plot3D.java. --- 87 3-D Plot/java/Plot3D.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/87 3-D Plot/java/Plot3D.java b/87 3-D Plot/java/Plot3D.java index 77ffbb8d..a12848d8 100644 --- a/87 3-D Plot/java/Plot3D.java +++ b/87 3-D Plot/java/Plot3D.java @@ -94,4 +94,4 @@ public class Plot3D { } // End of method main -} // End of class Plot3D \ No newline at end of file +} // End of class Plot3D From 6ca81063457d319121d13b8cf2cae7c29678e0e7 Mon Sep 17 00:00:00 2001 From: Ignacio Manzano Date: Mon, 22 Mar 2021 09:12:26 -0300 Subject: [PATCH 25/32] Boxing 15 - ported to java --- 15 Boxing/java/Basic.java | 45 +++++++ 15 Boxing/java/Boxing.java | 227 ++++++++++++++++++++++++++++++++ 15 Boxing/java/BoxingGame.java | 6 + 15 Boxing/java/GameSession.java | 67 ++++++++++ 15 Boxing/java/Player.java | 42 ++++++ 15 Boxing/java/Punch.java | 27 ++++ 66 Number/java/main.class | 69 ++++++++++ 7 files changed, 483 insertions(+) create mode 100644 15 Boxing/java/Basic.java create mode 100644 15 Boxing/java/Boxing.java create mode 100644 15 Boxing/java/BoxingGame.java create mode 100644 15 Boxing/java/GameSession.java create mode 100644 15 Boxing/java/Player.java create mode 100644 15 Boxing/java/Punch.java create mode 100644 66 Number/java/main.class diff --git a/15 Boxing/java/Basic.java b/15 Boxing/java/Basic.java new file mode 100644 index 00000000..3822e3f3 --- /dev/null +++ b/15 Boxing/java/Basic.java @@ -0,0 +1,45 @@ +import java.util.Scanner; + +/** + * It provide some kind of BASIC language behaviour simulations. + */ +final class Basic { + + public static int randomOf(int base) { + return (int)Math.round(Math.floor(base* Math.random() + 1)); + } + + /** + * The Console "simulate" the message error when input does not match with the expected type. + * Specifically for this game if you enter an String when and int was expected. + */ + public static class Console { + private final Scanner input = new Scanner(System.in); + + public String readLine() { + return input.nextLine(); + } + + public int readInt() { + int ret = -1; + boolean failedInput = true; + do { + boolean b = input.hasNextInt(); + if (b) { + ret = input.nextInt(); + failedInput = false; + } else { + input.next(); // discard read + System.out.print("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } while (failedInput); + + return ret; + } + + public void print(String message, Object... args) { + System.out.printf(message, args); + } + } +} \ No newline at end of file diff --git a/15 Boxing/java/Boxing.java b/15 Boxing/java/Boxing.java new file mode 100644 index 00000000..64b20155 --- /dev/null +++ b/15 Boxing/java/Boxing.java @@ -0,0 +1,227 @@ +/** + * Boxing + * + *

+ * Based on the Basic game of BatNum here + * https://github.com/coding-horror/basic-computer-games/tree/main/15%20Boxing + *

+ */ +public class Boxing { + + private static final Basic.Console console = new Basic.Console(); + + private GameSession session; + + public void play() { + showIntro(); + + loadPlayers(); + + console.print("%s'S ADVANTAGE IS %d AND VULNERABILITY IS SECRET.\n", session.getOpponent().getName(), session.getOpponent().getBestPunch().getCode()); + + + for (int roundNro = 1; roundNro <= 3; roundNro++) { + if (session.isOver()) + break; + + session.resetPoints(); + console.print("\nROUND %d BEGINS...%n", roundNro); + + for (int majorPunches = 1; majorPunches <= 7; majorPunches++) { + long i = Basic.randomOf(10); + + if (i > 5) { + boolean stopPunches = opponentPunch(); + if (stopPunches ) break; + } else { + playerPunch(); + } + } + showRoundWinner(roundNro); + } + showWinner(); + } + + private boolean opponentPunch() { + final Punch punch = Punch.random(); + + if (punch == session.getOpponent().getBestPunch()) session.addOpponentPoints(2); + + if (punch == Punch.FULL_SWING) { + console.print("%s TAKES A FULL SWING AND", session.getOpponent().getName()); + long r6 = Basic.randomOf(60); + + if (session.getPlayer().hitVulnerability(Punch.FULL_SWING) || r6 < 30) { + console.print(" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\n"); + if (session.getPoints(session.getOpponent()) > 35) { + + session.setKnocked(); + return true; + } + session.addOpponentPoints(15); + } else { + console.print(" IT'S BLOCKED!\n"); + } + } + + if (punch == Punch.HOOK || punch == Punch.UPPERCUT) { + if (punch == Punch.HOOK) { + console.print("%s GETS %s IN THE JAW (OUCH!)\n", session.getOpponent().getName(), session.getPlayer().getName()); + + session.addOpponentPoints(7); + console.print("....AND AGAIN!\n"); + + session.addOpponentPoints(5); + if (session.getPoints(session.getOpponent()) > 35) { + session.setKnocked(); + return true; + } + console.print("\n"); + + } + console.print("%s IS ATTACKED BY AN UPPERCUT (OH,OH)...\n", session.getPlayer().getName()); + long q4 = Basic.randomOf(200); + if (session.getPlayer().hitVulnerability(Punch.UPPERCUT) || q4 <= 75) { + console.print("AND %s CONNECTS...\n", session.getOpponent().getName()); + + session.addOpponentPoints(8); + } else { + console.print(" BLOCKS AND HITS %s WITH A HOOK.\n", session.getOpponent().getName()); + + session.addPlayerPoints(5); + } + } + else { + console.print("%s JABS AND ", session.getOpponent().getName()); + long z4 = Basic.randomOf(7); + if (session.getPlayer().hitVulnerability(Punch.JAB)) + + session.addOpponentPoints(5); + else if (z4 > 4) { + console.print(" BLOOD SPILLS !!!\n"); + + session.addOpponentPoints(5); + } else { + console.print("IT'S BLOCKED!\n"); + } + } + return true; + } + + private void playerPunch() { + console.print("%s'S PUNCH? ", session.getPlayer().getName()); + final Punch punch = Punch.fromCode(console.readInt()); + + if (punch == session.getPlayer().getBestPunch()) session.addPlayerPoints(2); + + switch (punch) { + case FULL_SWING -> { + console.print("%s SWINGS AND ", session.getPlayer().getName()); + if (session.getOpponent().getBestPunch() == Punch.JAB) { + console.print("HE CONNECTS!\n"); + if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15); + } else { + long x3 = Basic.randomOf(30); + if (x3 < 10) { + console.print("HE CONNECTS!\n"); + if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15); + } else { + console.print("HE MISSES \n"); + if (session.getPoints(session.getPlayer()) != 1) console.print("\n\n"); + } + } + } + case HOOK -> { + console.print("\n%s GIVES THE HOOK... ", session.getPlayer().getName()); + long h1 = Basic.randomOf(2); + if (session.getOpponent().getBestPunch() == Punch.HOOK) { + + session.addPlayerPoints(7); + } else if (h1 == 1) { + console.print("BUT IT'S BLOCKED!!!!!!!!!!!!!\n"); + } else { + console.print("CONNECTS...\n"); + + session.addPlayerPoints(7); + } + } + case UPPERCUT -> { + console.print("\n%s TRIES AN UPPERCUT ", session.getPlayer().getName()); + long d5 = Basic.randomOf(100); + if (session.getOpponent().getBestPunch() == Punch.UPPERCUT || d5 < 51) { + console.print("AND HE CONNECTS!\n"); + + session.addPlayerPoints(4); + } else { + console.print("AND IT'S BLOCKED (LUCKY BLOCK!)\n"); + } + } + default -> { + console.print("%s JABS AT %s'S HEAD \n", session.getPlayer().getName(), session.getOpponent().getName()); + if (session.getOpponent().getBestPunch() == Punch.JAB) { + + session.addPlayerPoints(3); + } else { + long c = Basic.randomOf(8); + if (c < 4) { + console.print("IT'S BLOCKED.\n"); + } else { + + session.addPlayerPoints(3); + } + } + } + } + } + + private void showRoundWinner(int roundNro) { + if (session.isRoundWinner(session.getPlayer())) { + console.print("\n %s WINS ROUND %d\n", session.getPlayer().getName(), roundNro); + session.addRoundWind(session.getPlayer()); + } else { + console.print("\n %s WINS ROUND %d\n", session.getOpponent().getName(), roundNro); + session.addRoundWind(session.getOpponent()); + } + } + + private void showWinner() { + if (session.isGameWinner(session.getOpponent())) { + console.print("%s WINS (NICE GOING, " + session.getOpponent().getName() + ").", session.getOpponent().getName()); + } else if (session.isGameWinner(session.getPlayer())) { + console.print("%s AMAZINGLY WINS!!", session.getPlayer().getName()); + } else if (session.isPlayerKnocked()) { + console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getPlayer().getName(), session.getOpponent().getName()); + } else { + console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getOpponent().getName(), session.getPlayer().getName()); + } + + console.print("\n\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\n"); + } + + private void loadPlayers() { + console.print("WHAT IS YOUR OPPONENT'S NAME? "); + final String opponentName = console.readLine(); + + console.print("INPUT YOUR MAN'S NAME? "); + final String playerName = console.readLine(); + + console.print("DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\n"); + console.print("WHAT IS YOUR MANS BEST? "); + + final int b = console.readInt(); + + console.print("WHAT IS HIS VULNERABILITY? "); + final int d = console.readInt(); + + final Player player = new Player(playerName, Punch.fromCode(b), Punch.fromCode(d)); + final Player opponent = new Player(opponentName); + + session = new GameSession(player, opponent); + } + + private void showIntro () { + console.print(" BOXING\n"); + console.print(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"); + console.print("BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\n\n"); + } +} \ No newline at end of file diff --git a/15 Boxing/java/BoxingGame.java b/15 Boxing/java/BoxingGame.java new file mode 100644 index 00000000..5e5f897b --- /dev/null +++ b/15 Boxing/java/BoxingGame.java @@ -0,0 +1,6 @@ +public class BoxingGame { + + public static void main(String[] args) { + new Boxing().play(); + } +} diff --git a/15 Boxing/java/GameSession.java b/15 Boxing/java/GameSession.java new file mode 100644 index 00000000..3a2c77a5 --- /dev/null +++ b/15 Boxing/java/GameSession.java @@ -0,0 +1,67 @@ +/** + * Game Session + * The session store the state of the game + */ +public class GameSession { + private final Player player; + private final Player opponent; + private int opponentRoundWins = 0; + private int playerRoundWins = 0; + + int playerPoints = 0; + int opponentPoints = 0; + boolean knocked = false; + + GameSession(Player player, Player opponent) { + this.player = player; + this.opponent = opponent; + } + + public Player getPlayer() { return player;} + public Player getOpponent() { return opponent;} + + public void setKnocked() { + knocked = true; + } + + public void resetPoints() { + playerPoints = 0; + opponentPoints = 0; + } + + public void addPlayerPoints(int ptos) { playerPoints+=ptos;} + public void addOpponentPoints(int ptos) { opponentPoints+=ptos;} + + public int getPoints(Player player) { + if(player.isPlayer()) + return playerPoints; + else + return opponentPoints; + } + + public void addRoundWind(Player player) { + if(player.isPlayer()) playerRoundWins++; else opponentRoundWins++; + } + + public boolean isOver() { + return (opponentRoundWins >= 2 || playerRoundWins >= 2); + } + + public boolean isRoundWinner(Player player) { + if (player.isPlayer()) + return playerPoints > opponentPoints; + else + return opponentPoints > playerPoints; + } + + public boolean isGameWinner(Player player) { + if (player.isPlayer()) + return playerRoundWins > 2; + else + return opponentRoundWins > 2; + } + + public boolean isPlayerKnocked() { + return knocked; + } +} \ No newline at end of file diff --git a/15 Boxing/java/Player.java b/15 Boxing/java/Player.java new file mode 100644 index 00000000..2462b9d0 --- /dev/null +++ b/15 Boxing/java/Player.java @@ -0,0 +1,42 @@ +/** + * The Player class model the user and compuer player + */ +public class Player { + private final String name; + private final Punch bestPunch; + private final Punch vulnerability; + private boolean isPlayer = false; + + public Player(String name, Punch bestPunch, Punch vulnerability) { + this.name = name; + this.bestPunch = bestPunch; + this.vulnerability = vulnerability; + this.isPlayer = true; + } + + /** + * Player with random Best Punch and Vulnerability + */ + public Player(String name) { + this.name = name; + + int b1; + int d1; + + do { + b1 = Basic.randomOf(4); + d1 = Basic.randomOf(4); + } while (b1 == d1); + + this.bestPunch = Punch.fromCode(b1); + this.vulnerability = Punch.fromCode(d1); + } + + public boolean isPlayer() { return isPlayer; } + public String getName() { return name; } + public Punch getBestPunch() { return bestPunch; } + + public boolean hitVulnerability(Punch punch) { + return vulnerability == punch; + } +} \ No newline at end of file diff --git a/15 Boxing/java/Punch.java b/15 Boxing/java/Punch.java new file mode 100644 index 00000000..24745b92 --- /dev/null +++ b/15 Boxing/java/Punch.java @@ -0,0 +1,27 @@ +import java.util.Arrays; + +/** + * Types of Punches + */ +public enum Punch { + FULL_SWING(1), + HOOK(2), + UPPERCUT(3), + JAB(4); + + private final int code; + + Punch(int code) { + this.code = code; + } + + int getCode() { return code;} + + public static Punch fromCode(int code) { + return Arrays.stream(Punch.values()).filter(p->p.code == code).findAny().orElse(null); + } + + public static Punch random() { + return Punch.fromCode(Basic.randomOf(4)); + } +} diff --git a/66 Number/java/main.class b/66 Number/java/main.class new file mode 100644 index 00000000..c3df4ebf --- /dev/null +++ b/66 Number/java/main.class @@ -0,0 +1,69 @@ + +import java.time.temporal.ValueRange; +import java.util.Arrays; +import java.util.Random; +import java.util.Scanner; + +public class Number { + + public static int points = 0; + + public static void printempty() { System.out.println(" "); } + + public static void print(String toprint) { System.out.println(toprint); } + + public static void main(String[] args) { + print("YOU HAVE 100 POINTS. BY GUESSING NUMBERS FROM 1 TO 5, YOU"); + print("CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO"); + print("A RANDOM NUMBER SELECTED BY THE COMPUTER."); + printempty(); + print("YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)"); + print("YOUR POINT COUNT. YOU WIN WHEN YOU GET 500 POINTS."); + printempty(); + + try { + while (true) { + print("GUESS A NUMBER FROM 1 TO 5"); + + + Scanner numbersc = new Scanner(System.in); + String numberstring = numbersc.nextLine(); + + int number = Integer.parseInt(numberstring); + + if (!(number < 1| number > 5)) { + + Random rand = new Random(); + + int randomNum = rand.nextInt((5 - 1) + 1) + 1; + + if (randomNum == number) { + print("YOU HIT THE JACKPOT!!!"); + points = points * 2; + } else if(ValueRange.of(randomNum, randomNum + 1).isValidIntValue(number)) { + print("+5"); + points = points + 5; + } else if(ValueRange.of(randomNum - 1, randomNum + 2).isValidIntValue(number)) { + print("+1"); + points = points + 1; + } else if(ValueRange.of(randomNum - 3, randomNum + 1).isValidIntValue(number)) { + print("-1"); + points = points - 1; + } else { + print("-half"); + points = (int) (points * 0.5); + } + + print("YOU HAVE " + points + " POINTS."); + } + + if (points >= 500) { + print("!!!!YOU WIN!!!! WITH " + points + " POINTS."); + return; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} From 5d97639ed139e501f40425af49674734e20d7386 Mon Sep 17 00:00:00 2001 From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:29:41 -0400 Subject: [PATCH 26/32] Ported Hello game to Java. --- 45 Hello/java/Hello.java | 216 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 45 Hello/java/Hello.java diff --git a/45 Hello/java/Hello.java b/45 Hello/java/Hello.java new file mode 100644 index 00000000..7807a2dd --- /dev/null +++ b/45 Hello/java/Hello.java @@ -0,0 +1,216 @@ +import java.util.Scanner; + +/** + * Game of Hello + *

+ * Based on the BASIC game of Hello here + * https://github.com/coding-horror/basic-computer-games/blob/main/45%20Hello/hello.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class Hello { + + private static final int MONEY_WAIT_MS = 3000; + + private final boolean goodEnding = false; + + private final Scanner scan; // For user input + + public Hello() { + + scan = new Scanner(System.in); + + } // End of constructor Hello + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(32) + "HELLO"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + boolean moreProblems = true; + + String userCategory = ""; + String userName = ""; + String userResponse = ""; + + // Name question + System.out.println("HELLO. MY NAME IS CREATIVE COMPUTER.\n\n"); + System.out.print("WHAT'S YOUR NAME? "); + userName = scan.nextLine(); + System.out.println(""); + + // Enjoyment question + System.out.print("HI THERE, " + userName + ", ARE YOU ENJOYING YOURSELF HERE? "); + + while (true) { + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.println("I'M GLAD TO HEAR THAT, " + userName + ".\n"); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println("OH, I'M SORRY TO HEAR THAT, " + userName + ". MAYBE WE CAN"); + System.out.println("BRIGHTEN UP YOUR VISIT A BIT."); + break; + } + else { + System.out.println(userName + ", I DON'T UNDERSTAND YOUR ANSWER OF '" + userResponse + "'."); + System.out.print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE? "); + } + } + + // Category question + System.out.println(""); + System.out.println("SAY, " + userName + ", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT"); + System.out.println("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO"); + System.out.print("YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? "); + + while (moreProblems) { + userCategory = scan.nextLine(); + System.out.println(""); + + // Sex advice + if (userCategory.toUpperCase().equals("SEX")) { + System.out.print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE? "); + userResponse = scan.nextLine(); + System.out.println(""); + + while (true) { + if (userResponse.toUpperCase().equals("TOO MUCH")) { + System.out.println("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!"); + System.out.println("IF IT BOTHERS YOU, " + userName + ", TAKE A COLD SHOWER."); + break; + } + else if (userResponse.toUpperCase().equals("TOO LITTLE")) { + System.out.println("WHY ARE YOU HERE IN SUFFERN, " + userName + "? YOU SHOULD BE"); + System.out.println("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME"); + System.out.println("REAL ACTION."); + break; + } + else { + System.out.println("DON'T GET ALL SHOOK, " + userName + ", JUST ANSWER THE QUESTION"); + System.out.print("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? "); + userResponse = scan.nextLine(); + } + } + } + // Health advice + else if (userCategory.toUpperCase().equals("HEALTH")) { + System.out.println("MY ADVICE TO YOU " + userName + " IS:"); + System.out.println(" 1. TAKE TWO ASPRIN"); + System.out.println(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)"); + System.out.println(" 3. GO TO BED (ALONE)"); + } + // Money advice + else if (userCategory.toUpperCase().equals("MONEY")) { + System.out.println("SORRY, " + userName + ", I'M BROKE TOO. WHY DON'T YOU SELL"); + System.out.println("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING"); + System.out.println("SO YOU WON'T NEED SO MUCH MONEY?"); + } + // Job advice + else if (userCategory.toUpperCase().equals("JOB")) { + System.out.println("I CAN SYMPATHIZE WITH YOU " + userName + ". I HAVE TO WORK"); + System.out.println("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES"); + System.out.println("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, " + userName + ","); + System.out.println("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN."); + } + else { + System.out.println("OH, " + userName + ", YOUR ANSWER OF " + userCategory + " IS GREEK TO ME."); + } + + // More problems question + while (true) { + System.out.println(""); + System.out.print("ANY MORE PROBLEMS YOU WANT SOLVED, " + userName + "? "); + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.print("WHAT KIND (SEX, MONEY, HEALTH, JOB)? "); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + moreProblems = false; + break; + } + else { + System.out.println("JUST A SIMPLE 'YES' OR 'NO' PLEASE, " + userName + "."); + } + } + } + + // Payment question + System.out.println(""); + System.out.println("THAT WILL BE $5.00 FOR THE ADVICE, " + userName + "."); + System.out.println("PLEASE LEAVE THE MONEY ON THE TERMINAL."); + + // Pause + try { + Thread.sleep(MONEY_WAIT_MS); + } catch (Exception e) { + System.out.println("Caught Exception: " + e.getMessage()); + } + + System.out.println("\n\n"); + + while (true) { + System.out.print("DID YOU LEAVE THE MONEY? "); + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.println("HEY, " + userName + "??? YOU LEFT NO MONEY AT ALL!"); + System.out.println("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING."); + System.out.println(""); + System.out.println("WHAT A RIP OFF, " + userName + "!!!\n"); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println("THAT'S HONEST, " + userName + ", BUT HOW DO YOU EXPECT"); + System.out.println("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS"); + System.out.println("DON'T PAY THEIR BILLS?"); + break; + } + else { + System.out.println("YOUR ANSWER OF '" + userResponse + "' CONFUSES ME, " + userName + "."); + System.out.println("PLEASE RESPOND WITH 'YES' OR 'NO'."); + } + } + + // Legacy included unreachable code + if (goodEnding) { + System.out.println("NICE MEETING YOU, " + userName + ", HAVE A NICE DAY."); + } + else { + System.out.println(""); + System.out.println("TAKE A WALK, " + userName + ".\n"); + } + + } // End of method startGame + + public static void main(String[] args) { + + Hello hello = new Hello(); + hello.play(); + + } // End of method main + +} // End of class Hello From 69e72720b461bee4e6acf9d5a845a689ece55c6f Mon Sep 17 00:00:00 2001 From: nanochess Date: Mon, 22 Mar 2021 21:41:30 -0600 Subject: [PATCH 27/32] Ported GOLF to Javascript --- 39 Golf/javascript/golf.html | 9 + 39 Golf/javascript/golf.js | 369 +++++++++++++++++++++++++++++++++++ 2 files changed, 378 insertions(+) create mode 100644 39 Golf/javascript/golf.html create mode 100644 39 Golf/javascript/golf.js diff --git a/39 Golf/javascript/golf.html b/39 Golf/javascript/golf.html new file mode 100644 index 00000000..bf43de8e --- /dev/null +++ b/39 Golf/javascript/golf.html @@ -0,0 +1,9 @@ + + +GOLF + + +


+
+
+
diff --git a/39 Golf/javascript/golf.js b/39 Golf/javascript/golf.js
new file mode 100644
index 00000000..814d589e
--- /dev/null
+++ b/39 Golf/javascript/golf.js	
@@ -0,0 +1,369 @@
+// GOLF
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var la = [];
+var f;
+var s1;
+var g2;
+var g3;
+var x;
+
+var hole_data = [
+    361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2,
+    408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4,
+    196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2,
+    357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2,
+    180,3,6,2,550,5,6,6,
+];
+
+function show_obstacle()
+{
+    switch (la[x]) {
+        case 1:
+            print("FAIRWAY.\n");
+            break;
+        case 2:
+            print("ROUGH.\n");
+            break;
+        case 3:
+            print("TREES.\n");
+            break;
+        case 4:
+            print("ADJACENT FAIRWAY.\n");
+            break;
+        case 5:
+            print("TRAP.\n");
+            break;
+        case 6:
+            print("WATER.\n");
+            break;
+    }
+}
+
+function show_score()
+{
+    g2 += s1;
+    print("TOTAL PAR FOR " + (f - 1) + " HOLES IS " + g3 + "  YOUR TOTAL IS " + g2 + "\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(34) + "GOLF\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\n");
+    print("AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\n");
+    print("DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE\n");
+    print("COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\n");
+    print("ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\n");
+    print("\n");
+    print("\n");
+    next_hole = 0;
+    g1 = 18;
+    g2 = 0;
+    g3 = 0;
+    a = 0;
+    n = 0.8;
+    s2 = 0;
+    f = 1;
+    while (1) {
+        print("WHAT IS YOUR HANDICAP");
+        h = parseInt(await input());
+        print("\n");
+        if (h < 0 || h > 30) {
+            print("PGA HANDICAPS RANGE FROM 0 TO 30.\n");
+        } else {
+            break;
+        }
+    }
+    do {
+        print("DIFFICULTIES AT GOLF INCLUDE:\n");
+        print("0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\n");
+        print("WHICH ONE (ONLY ONE) IS YOUR WORST");
+        t = parseInt(await input());
+        print("\n");
+    } while (t > 5) ;
+    s1 = 0;
+    first_routine = true;
+    while (1) {
+        if (first_routine) {
+            la[0] = 0;
+            j = 0;
+            q = 0;
+            s2++;
+            k = 0;
+            if (f != 1) {
+                print("YOUR SCORE ON HOLE " + (f - 1) + " WAS " + s1 + "\n");
+                show_score();
+                if (g1 == f - 1)    // Completed all holes?
+                    return;         // Exit game
+                if (s1 > p + 2) {
+                    print("KEEP YOUR HEAD DOWN.\n");
+                } else if (s1 == p) {
+                    print("A PAR.  NICE GOING.\n");
+                } else if (s1 == p - 1) {
+                    print("A BIRDIE.\n");
+                } else if (s1 == p - 2) {
+                    if (p != 3)
+                        print("A GREAT BIG EAGLE.\n");
+                    else
+                        print("A HOLE IN ONE.\n");
+                }
+            }
+            if (f == 19) {
+                print("\n");
+                show_score();
+                if (g1 == f - 1)
+                    return;
+            }
+            s1 = 0;
+            print("\n");
+            if (s1 != 0 && la[0] < 1)
+                la[0] = 1;
+        }
+        if (s1 == 0) {
+            d = hole_data[next_hole++];
+            p = hole_data[next_hole++];
+            la[1] = hole_data[next_hole++];
+            la[2] = hole_data[next_hole++];
+            print("\n");
+            print("YOU ARE AT THE TEE OFF HOLE " + f + " DISTANCE " + d + " YARDS, PAR " + p + "\n");
+            g3 += p;
+            print("ON YOUR RIGHT IS ");
+            x = 1;
+            show_obstacle();
+            print("ON YOUR LEFT IS ");
+            x = 2
+            show_obstacle();
+        } else {
+            x = 0;
+            if (la[0] > 5) {
+                if (la[0] > 6) {
+                    print("YOUR SHOT WENT OUT OF BOUNDS.\n");
+                } else {
+                    print("YOUR SHOT WENT INTO THE WATER.\n");
+                }
+                s1++;
+                print("PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION.\n");
+                j++;
+                la[0] = 1;
+                d = b;
+            } else {
+                print("SHOT WENT " + d1 + " YARDS.  IT'S " + d2 + " YARDS FROM THE CUP.\n");
+                print("BALL IS " + Math.floor(o) + " YARDS OFF LINE... IN ");
+                show_obstacle();
+            }
+        }
+        
+        while (1) {
+            if (a != 1) {
+                print("SELECTION OF CLUBS\n");
+                print("YARDAGE DESIRED                       SUGGESTED CLUBS\n");
+                print("200 TO 280 YARDS                           1 TO 4\n");
+                print("100 TO 200 YARDS                          19 TO 13\n");
+                print("  0 TO 100 YARDS                          29 TO 23\n");
+                a = 1;
+            }
+            print("WHAT CLUB DO YOU CHOOSE");
+            c = parseInt(await input());
+            print("\n");
+            if (c >= 1 && c <= 29 && (c < 5 || c >= 12)) {
+                if (c > 4)
+                    c -= 6;
+                if (la[0] <= 5 || c == 14 || c == 23) {
+                    s1++;
+                    w = 1;
+                    if (c <= 13) {
+                        if (f % 3 == 0 && s2 + q + (10 * (f - 1) / 18) < (f - 1) * (72 + ((h + 1) / 0.85)) / 18) {
+                            q++;
+                            if (s1 % 2 != 0 && d >= 95) {
+                                print("BALL HIT TREE - BOUNCED INTO ROUGH " + (d - 75) + " YARDS FROM HOLE.\n");
+                                d -= 75;
+                                continue;
+                            }
+                            print("YOU DUBBED IT.\n");
+                            d1 = 35;
+                            second_routine = 1;
+                            break;
+                        } else if (c < 4 && la[0] == 2) {
+                            print("YOU DUBBED IT.\n");
+                            d1 = 35;
+                            second_routine = 1;
+                            break;
+                        } else {
+                            second_routine = 0;
+                            break;
+                        }
+                    } else {
+                        print("NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\n");
+                        print("OF A FULL SWING");
+                        w = parseInt(await input());
+                        w /= 100;
+                        print("\n");
+                        if (w <= 1) {
+                            if (la[0] == 5) {
+                                if (t == 3) {
+                                    if (Math.random() <= n) {
+                                        n *= 0.2;
+                                        print("SHOT DUBBED, STILL IN TRAP.\n");
+                                        continue;
+                                    }
+                                    n = 0.8;
+                                }
+                                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
+                                second_routine = 2;
+                                break;
+                            }
+                            if (c != 14)
+                                c -= 10;
+                            second_routine = 0;
+                            break;
+                        }
+                        s1--;
+                        // Fall through to THAT CLUB IS NOT IN THE BAG.
+                    }
+                }
+            }
+            print("THAT CLUB IS NOT IN THE BAG.\n");
+            print("\n");
+        }
+        if (second_routine == 0) {
+            if (s1 > 7 && d < 200) {
+                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
+                second_routine = 2;
+            } else {
+                d1 = Math.floor(((30 - h) * 2.5 + 187 - ((30 - h) * 0.25 + 15) * c / 2) + 25 * Math.random());
+                d1 = Math.floor(d1 * w);
+                if (t == 2)
+                    d1 = Math.floor(d1 * 0.85);
+            }
+        }
+        if (second_routine <= 1) {
+            o = (Math.random() / 0.8) * (2 * h + 16) * Math.abs(Math.tan(d1 * 0.0035));
+            d2 = Math.floor(Math.sqrt(Math.pow(o, 2) + Math.pow(Math.abs(d - d1), 2)));
+            if (d - d1 < 0) {
+                if (d2 >= 20)
+                    print("TOO MUCH CLUB, YOU'RE PAST THE HOLE.\n");
+            }
+            b = d;
+            d = d2;
+            if (d2 > 27) {
+                if (o < 30 || j > 0) {
+                    la[0] = 1;
+                } else {
+                    if (t <= 0) {
+                        s9 = (s2 + 1) / 15;
+                        if (Math.floor(s9) == s9) {
+                            print("YOU SLICED- ");
+                            la[0] = la[1];
+                        } else {
+                            print("YOU HOOKED- ");
+                            la[0] = la[2];
+                        }
+                    } else {
+                        s9 = (s2 + 1) / 15;
+                        if (Math.floor(s9) == s9) {
+                            print("YOU HOOKED- ");
+                            la[0] = la[2];
+                        } else {
+                            print("YOU SLICED- ");
+                            la[0] = la[1];
+                        }
+                    }
+                    if (o > 45)
+                        print("BADLY.\n");
+                }
+                first_routine = false;
+            } else if (d2 > 20) {
+                la[0] = 5;
+                first_routine = false;
+            } else if (d2 > 0.5) {
+                la[0] = 8;
+                d2 = Math.floor(d2 * 3);
+                second_routine = 2;
+            } else {
+                la[0] = 9;
+                print("YOU HOLED IT.\n");
+                print("\n");
+                f++;
+                first_routine = true;
+            }
+        }
+        if (second_routine == 2) {
+            while (1) {
+                print("ON GREEN, " + d2 + " FEET FROM THE PIN.\n");
+                print("CHOOSE YOUR PUTT POTENCY (1 TO 13):");
+                i = parseInt(await input());
+                s1++;
+                if (s1 + 1 - p <= (h * 0.072) + 2 && k <= 2) {
+                    k++;
+                    if (t == 4)
+                        d2 -= i * (4 + 1 * Math.random()) + 1;
+                    else
+                        d2 -= i * (4 + 2 * Math.random()) + 1.5;
+                    if (d2 < -2) {
+                        print("PASSED BY CUP.\n");
+                        d2 = Math.floor(-d2);
+                        continue;
+                    }
+                    if (d2 > 2) {
+                        print("PUTT SHORT.\n");
+                        d2 = Math.floor(d2);
+                        continue;
+                    }
+                }
+                print("YOU HOLED IT.\n");
+                print("\n");
+                f++;
+                break;
+            }
+            first_routine = true;
+        }
+    }
+}
+
+main();

From b8cb90fa08780ae5a73a1317984d4f2648dbaca5 Mon Sep 17 00:00:00 2001
From: Nezumi Ronin 
Date: Tue, 23 Mar 2021 02:34:53 -0600
Subject: [PATCH 28/32] Create love.pl

Made with Perl!
---
 58 Love/perl/love.pl | 54 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 58 Love/perl/love.pl

diff --git a/58 Love/perl/love.pl b/58 Love/perl/love.pl
new file mode 100644
index 00000000..9e9f95cc
--- /dev/null
+++ b/58 Love/perl/love.pl	
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "LOVE\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+print "A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\n";
+print "HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\n";
+print "YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\n";
+print "A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\n"; print "\n";
+print "YOUR MESSAGE, PLEASE? "; chomp(my $A = );
+my $L= length($A);
+
+
+#Original logic too fuzzy, remaked.
+my $Width= 60;
+my $Text= substr($A x ($Width/$L+1), 0, $Width);
+for (my $I=1; $I<10; $I++) { print "\n"; }
+
+my @Data= (
+	60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,
+	4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,
+	4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,
+	4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,
+	4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,
+	1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,
+	5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,
+	6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,
+	7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,
+	8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,
+	9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,
+	11,8,13,27,1,11,8,13,27,1,60
+	);
+
+
+my $Pos=0;
+my $Toggle=1;
+foreach my $Size (@Data) {
+	my $Chunk= $Toggle ? substr($Text, $Pos, $Size) : " " x $Size;
+	print $Chunk;
+	$Pos+= $Size;
+	$Toggle= !$Toggle;
+	if ($Pos>= $Width) {
+		print "\n";
+		$Toggle=1;
+		$Pos=0;
+		}
+	}
+
+for (my $I=1; $I<10; $I++) { print "\n"; }
+exit;
+
+

From 1e8527be81f2b746677846d75f669a1a1fec318c Mon Sep 17 00:00:00 2001
From: Nezumi Ronin 
Date: Tue, 23 Mar 2021 02:36:48 -0600
Subject: [PATCH 29/32] Create rockscissors.pl

Made with Perl!
---
 74 Rock Scissors Paper/perl/rockscissors.pl | 56 +++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 74 Rock Scissors Paper/perl/rockscissors.pl

diff --git a/74 Rock Scissors Paper/perl/rockscissors.pl b/74 Rock Scissors Paper/perl/rockscissors.pl
new file mode 100644
index 00000000..ac83f5cf
--- /dev/null
+++ b/74 Rock Scissors Paper/perl/rockscissors.pl	
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 21 . "GAME OF ROCK, SCISSORS, PAPER\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+
+my $Q=0;
+my $C=0;
+my $H=0;
+
+do {
+	print "HOW MANY GAMES? "; chomp($Q = );
+	if ($Q>10) { print "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\n"; }
+	} until ($Q<11);
+
+for (my $G=1; $G<=$Q; $G++) {
+	print "\n"; print "GAME NUMBER $G\n";
+	my $X=int(rand(1)*3+1);
+
+	my $K=0;
+	do {
+		print "3=ROCK...2=SCISSORS...1=PAPER\n";
+		print "1...2...3...WHAT'S YOUR CHOICE? "; chomp($K = );
+		if (($K-1)*($K-2)*($K-3)!=0) { print "INVALID.\n"; $K=0; } 
+		} until ($K!=0);
+
+
+	print "THIS IS MY CHOICE...\n";
+	if ($X==1) { print "...PAPER\n"; }
+	if ($X==2) { print "...SCISSORS\n"; }
+	if ($X==3) { print "...ROCK\n"; }
+
+	#Original logic too complex...
+	if ($X==$K) { print "TIE GAME. NO WINNER.\n"; next; }
+	my $Who=0;
+	if ($X==1 && $K==3) { $Who=1; } #Paper wins over rock.
+	if ($X==2 && $K==1) { $Who=1; } #Scissors wins over paper.
+	if ($X==3 && $K==2) { $Who=1; } #Rock wins over scissors.
+	if ($Who==1) {
+		print "WOW! I WIN!!!\n"; $C=$C+1;
+		} else {
+		print "YOU WIN!!!\n"; $H=$H+1;
+		}
+	}
+
+print "\n"; print "HERE IS THE FINAL GAME SCORE:\n";
+print "I HAVE WON $C GAME(S).\n";
+print "YOU HAVE WON $H GAME(S).\n";
+print "AND ".($Q-($C+$H))." GAME(S) ENDED IN A TIE.\n";
+print "\n"; print "THANKS FOR PLAYING!!\n";
+exit;
+
+

From 2aadba3da688ce8485981c523a4ff188c6230cb7 Mon Sep 17 00:00:00 2001
From: Nezumi Ronin 
Date: Tue, 23 Mar 2021 02:38:27 -0600
Subject: [PATCH 30/32] Create kinema.pl

Made with Perl!
---
 52 Kinema/perl/kinema.pl | 53 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 52 Kinema/perl/kinema.pl

diff --git a/52 Kinema/perl/kinema.pl b/52 Kinema/perl/kinema.pl
new file mode 100644
index 00000000..ef607983
--- /dev/null
+++ b/52 Kinema/perl/kinema.pl	
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "KINEMA\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+while (1) {
+	print "\n";
+	print "\n";
+	my $Q=0;
+	my $V=5+int(35*rand(1));
+	print "A BALL IS THROWN UPWARDS AT $V METERS PER SECOND.\n";
+	print "\n";
+
+	my $A=.05*$V^2;
+	print "HOW HIGH WILL IT GO (IN METERS)";
+	$Q+= &Input($A);
+
+	$A=$V/5;
+	print "HOW LONG UNTIL IT RETURNS (IN SECONDS)";
+	$Q+= &Input($A);
+
+	my $T=1+int(2*$V*rand(1))/10;
+	$A=$V-10*$T;
+	print "WHAT WILL ITS VELOCITY BE AFTER $T SECONDS";
+	$Q+= &Input($A);
+
+	print "\n";
+	print "$Q RIGHT OUT OF 3.";
+	if ($Q<2) { next; }
+	print " NOT BAD.\n";
+	}
+
+exit;
+
+
+#Line500:
+sub Input {
+	my ($A)= @_;
+	my $Point=0;
+	print "? "; chomp(my $G = );
+	if (abs(($G-$A)/$A)<.15) {
+		print "CLOSE ENOUGH.\n";
+		$Point=1;
+		} else {
+		print "NOT EVEN CLOSE....\n";
+		}
+	print "CORRECT ANSWER IS $A\n";
+	print "\n";
+	return $Point;
+	}

From 93fd68ac669065583d1d740cb843d48be5f0e5cd Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Tue, 23 Mar 2021 13:59:06 -0600
Subject: [PATCH 31/32] Ported LIFEFORTWO to Javascript

---
 37 Football/javascript/.DS_Store           | Bin 0 -> 6148 bytes
 56 Life for Two/javascript/lifefortwo.html |   9 +
 56 Life for Two/javascript/lifefortwo.js   | 209 +++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 37 Football/javascript/.DS_Store
 create mode 100644 56 Life for Two/javascript/lifefortwo.html
 create mode 100644 56 Life for Two/javascript/lifefortwo.js

diff --git a/37 Football/javascript/.DS_Store b/37 Football/javascript/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6
GIT binary patch
literal 6148
zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3
zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ
zLs35+`xjp>T0
+
+LIFE FOR TWO
+
+
+

+
+
+
diff --git a/56 Life for Two/javascript/lifefortwo.js b/56 Life for Two/javascript/lifefortwo.js
new file mode 100644
index 00000000..a8c90e50
--- /dev/null
+++ b/56 Life for Two/javascript/lifefortwo.js	
@@ -0,0 +1,209 @@
+// LIFE FOR TWO
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var na = [];
+var ka = [, 3,102,103,120,130,121,112,111,12,
+          21,30,1020,1030,1011,1021,1003,1002,1012];
+var aa = [,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1];
+var xa = [];
+var ya = [];
+var j;
+var k;
+var m2;
+var m3;
+
+function show_data()
+{
+    k = 0;
+    m2 = 0;
+    m3 = 0;
+    for (j = 0; j <= 6; j++) {
+        print("\n");
+        for (k = 0; k <= 6; k++) {
+            if (j == 0 || j == 6) {
+                if (k == 6)
+                    print(" 0 ");
+                else
+                    print(" " + k + " ");
+            } else if (k == 0 || k == 6) {
+                if (j == 6)
+                    print(" 0\n");
+                else
+                    print(" " + j + " ");
+            } else {
+                if (na[j][k] >= 3) {
+                    for (o1 = 1; o1 <= 18; o1++) {
+                        if (na[j][k] == ka[o1])
+                            break;
+                    }
+                    if (o1 <= 18) {
+                        if (o1 <= 9) {
+                            na[j][k] = 100;
+                            m2++;
+                            print(" * ");
+                        } else {
+                            na[j][k] = 1000;
+                            m3++;
+                            print(" # ");
+                        }
+                    } else {
+                        na[j][k] = 0;
+                        print("   ");
+                    }
+                } else {
+                    na[j][k] = 0;
+                    print("   ");
+                }
+            }
+        }
+    }
+}
+
+function process_board()
+{
+    for (j = 1; j <= 5; j++) {
+        for (k = 1; k <= 5; k++) {
+            if (na[j][k] > 99) {
+                b = 1;
+                if (na[j][k] > 999)
+                    b = 10;
+                for (o1 = 1; o1 <= 15; o1 += 2) {
+                    na[j + aa[o1]][k + aa[o1 + 1]] = na[j + aa[o1]][k + aa[o1 + 1]] + b;
+                }
+            }
+        }
+    }
+    show_data();
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "LIFE2\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print(tab(10) + "U.B. LIFE GAME\n");
+    m2 = 0;
+    m3 = 0;
+    for (j = 0; j <= 6; j++) {
+        na[j] = [];
+        for (k = 0; k <= 6; k++)
+            na[j][k] = 0;
+    }
+    for (b = 1; b <= 2; b++) {
+        p1 = (b == 2) ? 30 : 3;
+        print("\n");
+        print("PLAYER " + b + " - 3 LIVE PIECES.\n");
+        for (k1 = 1; k1 <= 3; k1++) {
+            while (1) {
+                print("X,Y\n");
+                str = await input();
+                ya[b] = parseInt(str);
+                xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
+                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
+                    break;
+                print("ILLEGAL COORDS. RETYPE\n");
+            }
+            if (b != 1) {
+                if (xa[1] == xa[2] && ya[1] == ya[2]) {
+                    print("SAME COORD.  SET TO 0\n");
+                    na[xa[b] + 1][ya[b] + 1] = 0;
+                    b = 99;
+                }
+            }
+            na[xa[b]][ya[b]] = p1;
+        }
+    }
+    show_data();
+    while (1) {
+        print("\n");
+        process_board();
+        if (m2 == 0 && m3 == 0) {
+            print("\n");
+            print("A DRAW\n");
+            break;
+        }
+        if (m3 == 0) {
+            print("\n");
+            print("PLAYER 1 IS THE WINNER\n");
+            break;
+        }
+        if (m2 == 0) {
+            print("\n");
+            print("PLAYER 2 IS THE WINNER\n");
+            break;
+        }
+        for (b = 1; b <= 2; b++) {
+            print("\n");
+            print("\n");
+            print("PLAYER " + b + " ");
+            while (1) {
+                print("X,Y\n");
+                str = await input();
+                ya[b] = parseInt(str);
+                xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
+                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
+                    break;
+                print("ILLEGAL COORDS. RETYPE\n");
+            }
+            if (b != 1) {
+                if (xa[1] == xa[2] && ya[1] == ya[2]) {
+                    print("SAME COORD.  SET TO 0\n");
+                    na[xa[b] + 1][ya[b] + 1] = 0;
+                    b = 99;
+                }
+            }
+            if (b == 99)
+                break;
+        }
+        if (b <= 2) {
+            na[x[1]][y[1]] = 100;
+            na[x[2]][y[2]] = 1000;
+        }
+    }
+}
+
+main();

From 9ce7100df6d911fbc42958b96a3dea1f33de504a Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Tue, 23 Mar 2021 22:17:04 -0600
Subject: [PATCH 32/32] Ported MASTERMIND to Javascript

---
 60 Mastermind/javascript/mastermind.html |   9 +
 60 Mastermind/javascript/mastermind.js   | 361 +++++++++++++++++++++++
 2 files changed, 370 insertions(+)
 create mode 100644 60 Mastermind/javascript/mastermind.html
 create mode 100644 60 Mastermind/javascript/mastermind.js

diff --git a/60 Mastermind/javascript/mastermind.html b/60 Mastermind/javascript/mastermind.html
new file mode 100644
index 00000000..e1835c05
--- /dev/null
+++ b/60 Mastermind/javascript/mastermind.html	
@@ -0,0 +1,9 @@
+
+
+MASTERMIND
+
+
+

+
+
+
diff --git a/60 Mastermind/javascript/mastermind.js b/60 Mastermind/javascript/mastermind.js
new file mode 100644
index 00000000..40d8139e
--- /dev/null
+++ b/60 Mastermind/javascript/mastermind.js	
@@ -0,0 +1,361 @@
+// MASTERMIND
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var p9;
+var c9;
+var b;
+var w;
+var f;
+var m;
+
+var qa;
+var sa;
+var ss;
+var as;
+var gs;
+var hs;
+
+function initialize_qa()
+{
+    for (s = 1; s <= p9; s++)
+        qa[s] = 0;
+}
+
+function increment_qa()
+{
+    if (qa[1] <= 0) {
+        // If zero, this is our firt increment: make all ones
+        for (s = 1; s <= p9; s++)
+            qa[s] = 1;
+    } else {
+        q = 1;
+        while (1) {
+            qa[q] = qa[q] + 1;
+            if (qa[q] <= c9)
+                return;
+            qa[q] = 1;
+            q++;
+        }
+    }
+}
+
+function convert_qa()
+{
+    for (s = 1; s <= p9; s++) {
+        as[s] = ls.substr(qa[s] - 1, 1);
+    }
+}
+
+function get_number()
+{
+    b = 0;
+    w = 0;
+    f = 0;
+    for (s = 1; s <= p9; s++) {
+        if (gs[s] == as[s]) {
+            b++;
+            gs[s] = String.fromCharCode(f);
+            as[s] = String.fromCharCode(f + 1);
+            f += 2;
+        } else {
+            for (t = 1; t <= p9; t++) {
+                if (gs[s] == as[t] && gs[t] != as[t]) {
+                    w++;
+                    as[t] = String.fromCharCode(f);
+                    gs[s] = String.fromCharCode(f + 1);
+                    f += 2;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+function convert_qa_hs()
+{
+    for (s = 1; s <= p9; s++) {
+        hs[s] = ls.substr(qa[s] - 1, 1);
+    }
+}
+
+function copy_hs()
+{
+    for (s = 1; s <= p9; s++) {
+        gs[s] = hs[s];
+    }
+}
+
+function board_printout()
+{
+    print("\n");
+    print("BOARD\n");
+    print("MOVE     GUESS          BLACK     WHITE\n");
+    for (z = 1; z <= m - 1; z++) {
+        str = " " + z + " ";
+        while (str.length < 9)
+            str += " ";
+        str += ss[z];
+        while (str.length < 25)
+            str += " ";
+        str += sa[z][1];
+        while (str.length < 35)
+            str += " ";
+        str += sa[z][2];
+        print(str + "\n");
+    }
+    print("\n");
+}
+
+function quit()
+{
+    print("QUITTER!  MY COMBINATION WAS: ");
+    convert_qa();
+    for (x = 1; x <= p9; x++) {
+        print(as[x]);
+    }
+    print("\n");
+    print("GOOD BYE\n");
+}
+
+function show_score()
+{
+    print("SCORE:\n");
+    show_points();
+}
+
+function show_points()
+{
+    print("     COMPUTER " + c + "\n");
+    print("     HUMAN    " + h + "\n");
+    print("\n");
+}
+
+var color = ["BLACK", "WHITE", "RED", "GREEN",
+             "ORANGE", "YELLOW", "PURPLE", "TAN"];
+
+// Main program
+async function main()
+{
+    print(tab(30) + "MASTERMIND\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    //
+    //  MASTERMIND II
+    //  STEVE NORTH
+    //  CREATIVE COMPUTING
+    //  PO BOX 789-M MORRISTOWN NEW JERSEY 07960
+    //
+    //
+    while (1) {
+        print("NUMBER OF COLORS");
+        c9 = parseInt(await input());
+        if (c9 <= 8)
+            break;
+        print("NO MORE THAN 8, PLEASE!\n");
+    }
+    print("NUMBER OF POSITIONS");
+    p9 = parseInt(await input());
+    print("NUMBER OF ROUNDS");
+    r9 = parseInt(await input());
+    p = Math.pow(c9, p9);
+    print("TOTAL POSSIBILITIES = " + p + "\n");
+    h = 0;
+    c = 0;
+    qa = [];
+    sa = [];
+    ss = [];
+    as = [];
+    gs = [];
+    ia = [];
+    hs = [];
+    ls = "BWRGOYPT";
+    print("\n");
+    print("\n");
+    print("COLOR    LETTER\n");
+    print("=====    ======\n");
+    for (x = 1; x <= c9; x++) {
+        str = color[x - 1];
+        while (str.length < 13)
+            str += " ";
+        str += ls.substr(x - 1, 1);
+        print(str + "\n");
+    }
+    print("\n");
+    for (r = 1; r <= r9; r++) {
+        print("\n");
+        print("ROUND NUMBER " + r + " ----\n");
+        print("\n");
+        print("GUESS MY COMBINATION.\n");
+        print("\n");
+        // Get a combination
+        a = Math.floor(p * Math.random() + 1);
+        initialize_qa();
+        for (x = 1; x <= a; x++) {
+            increment_qa();
+        }
+        for (m = 1; m <= 10; m++) {
+            while (1) {
+                print("MOVE # " + m + " GUESS ");
+                str = await input();
+                if (str == "BOARD") {
+                    board_printout();
+                } else if (str == "QUIT") {
+                    quit();
+                    return;
+                } else if (str.length != p9) {
+                    print("BAD NUMBER OF POSITIONS.\n");
+                } else {
+                    // Unpack str into gs(1-p9)
+                    for (x = 1; x <= p9; x++) {
+                        y = ls.indexOf(str.substr(x - 1, 1));
+                        if (y < 0) {
+                            print("'" + str.substr(x - 1, 1) + "' IS UNRECOGNIZED.\n");
+                            break;
+                        }
+                        gs[x] = str.substr(x - 1, 1);
+                    }
+                    if (x > p9)
+                        break;
+                }
+            }
+            // Now we convert qa(1-p9) into as(1-p9) [ACTUAL GUESS]
+            convert_qa();
+            // And get number of blacks and white
+            get_number();
+            if (b == p9) {
+                print("YOU GUESSED IT IN " + m + " MOVES!\n");
+                break;
+            }
+            // Save all this stuff for board printout later
+            ss[m] = str;
+            sa[m] = [];
+            sa[m][1] = b;
+            sa[m][2] = w;
+        }
+        if (m > 10) {
+            print("YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\n");
+        }
+        h += m;
+        show_score();
+        
+        //
+        // Now computer guesses
+        //
+        for (x = 1; x <= p; x++)
+            ia[x] = 1;
+        print("NOW I GUESS.  THINK OF A COMBINATION.\n");
+        print("HIT RETURN WHEN READY:");
+        str = await input();
+        for (m = 1; m <= 10; m++) {
+            initialize_qa();
+            // Find a guess
+            g = Math.floor(p * Math.random() + 1);
+            if (ia[g] != 1) {
+                for (x = g; x <= p; x++) {
+                    if (ia[x] == 1)
+                        break;
+                }
+                if (x > p) {
+                    for (x = 1; x <= g; x++) {
+                        if (ia[x] == 1)
+                            break;
+                    }
+                    if (x > g) {
+                        print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\n");
+                        print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\n");
+                        for (x = 1; x <= p; x++)
+                            ia[x] = 1;
+                        print("NOW I GUESS.  THINK OF A COMBINATION.\n");
+                        print("HIT RETURN WHEN READY:");
+                        str = await input();
+                        m = 0;
+                        continue;
+                    }
+                }
+                g = x;
+            }
+            // Now we convert guess #g into gs
+            for (x = 1; x <= g; x++) {
+                increment_qa();
+            }
+            convert_qa_hs();
+            print("MY GUESS IS: ");
+            for (x = 1; x <= p9; x++) {
+                print(hs[x]);
+            }
+            print("  BLACKS, WHITES ");
+            str = await input();
+            b1 = parseInt(str);
+            w1 = parseInt(str.substr(str.indexOf(",") + 1));
+            if (b1 == p9) {
+                print("I GOT IT IN " + m + " MOVES!\n");
+                break;
+            }
+            initialize_qa();
+            for (x = 1; x <= p; x++) {
+                increment_qa();
+                if (ia[x] != 0) {
+                    copy_hs();
+                    convert_qa();
+                    get_number();
+                    if (b1 != b || w1 != w)
+                        ia[x] = 0;
+                }
+            }
+        }
+        if (m > 10) {
+            print("I USED UP ALL MY MOVES!\n");
+            print("I GUESS MY CPU I JUST HAVING AN OFF DAY.\n");
+        }
+        c += m;
+        show_score();
+    }
+    print("GAME OVER\n");
+    print("FINAL SCORE:\n");
+    show_points();
+}
+
+main();