mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-19 00:06:04 -08:00
Main game loop with Short Range Scan and Shield Control
This commit is contained in:
34
84 Super Star Trek/csharp/Command.cs
Normal file
34
84 Super Star Trek/csharp/Command.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace SuperStarTrek
|
||||||
|
{
|
||||||
|
internal enum Command
|
||||||
|
{
|
||||||
|
[Description("To set course")]
|
||||||
|
NAV,
|
||||||
|
|
||||||
|
[Description("For short range sensor scan")]
|
||||||
|
SRS,
|
||||||
|
|
||||||
|
[Description("For long range sensor scan")]
|
||||||
|
LRS,
|
||||||
|
|
||||||
|
[Description("To fire phasers")]
|
||||||
|
PHA,
|
||||||
|
|
||||||
|
[Description("To fire photon torpedoes")]
|
||||||
|
TOR,
|
||||||
|
|
||||||
|
[Description("To raise or lower shields")]
|
||||||
|
SHE,
|
||||||
|
|
||||||
|
[Description("For damage control reports")]
|
||||||
|
DAM,
|
||||||
|
|
||||||
|
[Description("To call on library-computer")]
|
||||||
|
COM,
|
||||||
|
|
||||||
|
[Description("To resign your command")]
|
||||||
|
XXX
|
||||||
|
}
|
||||||
|
}
|
||||||
14
84 Super Star Trek/csharp/CommandExtensions.cs
Normal file
14
84 Super Star Trek/csharp/CommandExtensions.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace SuperStarTrek
|
||||||
|
{
|
||||||
|
internal static class CommandExtensions
|
||||||
|
{
|
||||||
|
internal static string GetDescription(this Command command) =>
|
||||||
|
typeof(Command)
|
||||||
|
.GetField(command.ToString())
|
||||||
|
.GetCustomAttribute<DescriptionAttribute>()
|
||||||
|
.Description;
|
||||||
|
}
|
||||||
|
}
|
||||||
97
84 Super Star Trek/csharp/Game.cs
Normal file
97
84 Super Star Trek/csharp/Game.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using SuperStarTrek.Objects;
|
||||||
|
using SuperStarTrek.Resources;
|
||||||
|
using SuperStarTrek.Space;
|
||||||
|
using SuperStarTrek.Systems;
|
||||||
|
using static System.StringComparison;
|
||||||
|
|
||||||
|
namespace SuperStarTrek
|
||||||
|
{
|
||||||
|
internal class Game
|
||||||
|
{
|
||||||
|
private readonly Output _output;
|
||||||
|
private readonly Input _input;
|
||||||
|
|
||||||
|
private int _initialStardate;
|
||||||
|
private int _finalStarDate;
|
||||||
|
private double _currentStardate;
|
||||||
|
private Coordinates _currentQuadrant;
|
||||||
|
private Coordinates _currentSector;
|
||||||
|
private Galaxy _galaxy;
|
||||||
|
private int _initialKlingonCount;
|
||||||
|
private Enterprise _enterprise;
|
||||||
|
|
||||||
|
public Game()
|
||||||
|
{
|
||||||
|
_output = new Output();
|
||||||
|
_input = new Input(_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Stardate => _currentStardate;
|
||||||
|
|
||||||
|
public void DoIntroduction()
|
||||||
|
{
|
||||||
|
_output.Write(Strings.Title);
|
||||||
|
|
||||||
|
_output.Write("Do you need instructions (Y/N)? ");
|
||||||
|
var response = Console.ReadLine();
|
||||||
|
_output.WriteLine();
|
||||||
|
|
||||||
|
if (!response.Equals("N", InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
_output.Write(Strings.Instructions);
|
||||||
|
|
||||||
|
_input.WaitForAnyKeyButEnter("to continue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Play()
|
||||||
|
{
|
||||||
|
var quadrant = Initialise();
|
||||||
|
var gameOver = false;
|
||||||
|
|
||||||
|
_output.Write(Strings.Enterprise);
|
||||||
|
_output.Write(
|
||||||
|
Strings.Orders,
|
||||||
|
_galaxy.KlingonCount,
|
||||||
|
_finalStarDate,
|
||||||
|
_finalStarDate - _initialStardate,
|
||||||
|
_galaxy.StarbaseCount > 1 ? "are" : "is",
|
||||||
|
_galaxy.StarbaseCount,
|
||||||
|
_galaxy.StarbaseCount > 1 ? "s" : "");
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
return new Quadrant(_galaxy[_currentQuadrant], _enterprise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye");
|
||||||
|
}
|
||||||
|
}
|
||||||
76
84 Super Star Trek/csharp/Input.cs
Normal file
76
84 Super Star Trek/csharp/Input.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using static System.StringComparison;
|
||||||
|
|
||||||
|
namespace SuperStarTrek
|
||||||
|
{
|
||||||
|
internal class Input
|
||||||
|
{
|
||||||
|
private readonly Output _output;
|
||||||
|
|
||||||
|
public Input(Output output)
|
||||||
|
{
|
||||||
|
_output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitForAnyKeyButEnter(string prompt)
|
||||||
|
{
|
||||||
|
_output.Write($"Hit any key but Enter {prompt} ");
|
||||||
|
while (Console.ReadKey(intercept: true).Key == ConsoleKey.Enter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetString(string prompt)
|
||||||
|
{
|
||||||
|
_output.Prompt(prompt);
|
||||||
|
return Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetNumber(string prompt)
|
||||||
|
{
|
||||||
|
_output.Prompt(prompt);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var response = Console.ReadLine();
|
||||||
|
if (double.TryParse(response, out var value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine("!Number expected - retry input line");
|
||||||
|
_output.Prompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetNumber(string prompt, double minValue, double maxValue, out double value)
|
||||||
|
{
|
||||||
|
value = GetNumber($"{prompt} ({minValue}-{maxValue})");
|
||||||
|
|
||||||
|
return value >= minValue && value <= maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool GetString(string replayPrompt, string trueValue)
|
||||||
|
=> GetString(replayPrompt).Equals(trueValue, InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
|
public Command GetCommand()
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
var response = GetString("Command");
|
||||||
|
|
||||||
|
if (response != "" &&
|
||||||
|
Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand))
|
||||||
|
{
|
||||||
|
return parsedCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine("Enter one of the following:");
|
||||||
|
foreach (var command in Enum.GetValues(typeof(Command)).OfType<Command>())
|
||||||
|
{
|
||||||
|
_output.WriteLine($" {command} ({command.GetDescription()})");
|
||||||
|
}
|
||||||
|
_output.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
84 Super Star Trek/csharp/Objects/Enterprise.cs
Normal file
103
84 Super Star Trek/csharp/Objects/Enterprise.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using SuperStarTrek.Resources;
|
||||||
|
using SuperStarTrek.Space;
|
||||||
|
using SuperStarTrek.Systems;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Objects
|
||||||
|
{
|
||||||
|
internal class Enterprise
|
||||||
|
{
|
||||||
|
private readonly int _maxEnergy;
|
||||||
|
private readonly List<Subsystem> _systems;
|
||||||
|
private readonly Dictionary<Command, Subsystem> _commandExecutors;
|
||||||
|
private Quadrant _quadrant;
|
||||||
|
private ShieldControl _shieldControl;
|
||||||
|
|
||||||
|
public Enterprise(int maxEnergy, Coordinates sector)
|
||||||
|
{
|
||||||
|
Sector = sector;
|
||||||
|
TotalEnergy = _maxEnergy = maxEnergy;
|
||||||
|
|
||||||
|
_systems = new List<Subsystem>();
|
||||||
|
_commandExecutors = new Dictionary<Command, Subsystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinates Quadrant => _quadrant.Coordinates;
|
||||||
|
public Coordinates Sector { get; }
|
||||||
|
public string Condition => GetCondition();
|
||||||
|
public double Shields => _shieldControl.Energy;
|
||||||
|
public double Energy => TotalEnergy - Shields;
|
||||||
|
public double TotalEnergy { get; private set; }
|
||||||
|
public int TorpedoCount { get; }
|
||||||
|
|
||||||
|
public bool IsDocked { get; private set; }
|
||||||
|
|
||||||
|
public Enterprise Add(Subsystem system)
|
||||||
|
{
|
||||||
|
_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;
|
||||||
|
|
||||||
|
var _output = new Output();
|
||||||
|
_output.Write(entryTextFormat, quadrant);
|
||||||
|
|
||||||
|
if (quadrant.HasKlingons)
|
||||||
|
{
|
||||||
|
_output.Write(Strings.CombatArea);
|
||||||
|
if (Shields <= 200) { _output.Write(Strings.LowShields); }
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDocked = quadrant.EnterpriseIsNextToStarbase;
|
||||||
|
|
||||||
|
Execute(Command.SRS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCondition() =>
|
||||||
|
(_quadrant.HasKlingons, Energy / _maxEnergy) switch
|
||||||
|
{
|
||||||
|
(true, _) => "*Red*",
|
||||||
|
(_, < 0.1) => "Yellow",
|
||||||
|
_ => "Green"
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool Execute(Command command)
|
||||||
|
{
|
||||||
|
_commandExecutors[command].ExecuteCommand(_quadrant);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool Recognises(string command)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetCommandList()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => "<*>";
|
||||||
|
}
|
||||||
|
}
|
||||||
14
84 Super Star Trek/csharp/Objects/Klingon.cs
Normal file
14
84 Super Star Trek/csharp/Objects/Klingon.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace SuperStarTrek.Objects
|
||||||
|
{
|
||||||
|
internal class Klingon
|
||||||
|
{
|
||||||
|
private double _energy;
|
||||||
|
|
||||||
|
public Klingon()
|
||||||
|
{
|
||||||
|
_energy = new Random().GetDouble(100, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => "+K+";
|
||||||
|
}
|
||||||
|
}
|
||||||
7
84 Super Star Trek/csharp/Objects/Star.cs
Normal file
7
84 Super Star Trek/csharp/Objects/Star.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace SuperStarTrek.Objects
|
||||||
|
{
|
||||||
|
internal class Star
|
||||||
|
{
|
||||||
|
public override string ToString() => " * ";
|
||||||
|
}
|
||||||
|
}
|
||||||
7
84 Super Star Trek/csharp/Objects/Starbase.cs
Normal file
7
84 Super Star Trek/csharp/Objects/Starbase.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace SuperStarTrek.Objects
|
||||||
|
{
|
||||||
|
internal class Starbase
|
||||||
|
{
|
||||||
|
public override string ToString() => ">!<";
|
||||||
|
}
|
||||||
|
}
|
||||||
15
84 Super Star Trek/csharp/Output.cs
Normal file
15
84 Super Star Trek/csharp/Output.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
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 void NextLine() => Console.WriteLine();
|
||||||
|
|
||||||
|
public void Prompt(string text = "") => Console.Write($"{text}? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,31 +23,20 @@
|
|||||||
// **** CONVERTED TO MICROSOFT C# 2/20/21 BY ANDREW COOPER
|
// **** CONVERTED TO MICROSOFT C# 2/20/21 BY ANDREW COOPER
|
||||||
// ****
|
// ****
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
using static System.StringComparison;
|
|
||||||
|
|
||||||
namespace SuperStarTrek
|
namespace SuperStarTrek
|
||||||
{
|
{
|
||||||
class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main()
|
||||||
{
|
{
|
||||||
Console.WriteLine(Strings.Title);
|
var game = new Game();
|
||||||
|
|
||||||
Console.Write("Do you need instructions (Y/N)? ");
|
game.DoIntroduction();
|
||||||
var response = Console.ReadLine();
|
|
||||||
Console.WriteLine();
|
|
||||||
|
|
||||||
if (!response.Equals("N", InvariantCultureIgnoreCase))
|
do
|
||||||
{
|
{
|
||||||
Console.WriteLine(Strings.Instructions);
|
game.Play();
|
||||||
|
} while (game.Replay());
|
||||||
Console.WriteLine("Press <Enter> to continue...");
|
|
||||||
Console.ReadLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(Strings.Enterprise);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
84 Super Star Trek/csharp/Random.cs
Normal file
25
84 Super Star Trek/csharp/Random.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using SuperStarTrek.Space;
|
||||||
|
|
||||||
|
namespace SuperStarTrek
|
||||||
|
{
|
||||||
|
internal class Random
|
||||||
|
{
|
||||||
|
private static readonly System.Random _random = new();
|
||||||
|
|
||||||
|
public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive(), Get1To8Inclusive());
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// 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 GetInt(int inclusiveMinValue, int exclusiveMaxValue) =>
|
||||||
|
_random.Next(inclusiveMinValue, exclusiveMaxValue);
|
||||||
|
|
||||||
|
public double GetDouble() => _random.NextDouble();
|
||||||
|
|
||||||
|
public double GetDouble(double inclusiveMinValue, double exclusiveMaxValue)
|
||||||
|
=> _random.NextDouble() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
84 Super Star Trek/csharp/Resources/CombatArea.txt
Normal file
1
84 Super Star Trek/csharp/Resources/CombatArea.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
COMBAT AREA CONDITION RED
|
||||||
@@ -53,7 +53,7 @@ LRS command = Long Range Sensor Scan
|
|||||||
The scan is coded in the form ###, where the units digit
|
The scan is coded in the form ###, where the units digit
|
||||||
is the number of stars, the tens digit is the number of
|
is the number of stars, the tens digit is the number of
|
||||||
starbases, and the hundreds digit is the number of
|
starbases, and the hundreds digit is the number of
|
||||||
Kilngons.
|
Klingons.
|
||||||
|
|
||||||
Example - 207 = 2 Klingons, No starbases, & 7 stars.
|
Example - 207 = 2 Klingons, No starbases, & 7 stars.
|
||||||
|
|
||||||
@@ -103,3 +103,4 @@ COM command = Library-Computer
|
|||||||
Option 5 = Galactic Region Name Map
|
Option 5 = Galactic Region Name Map
|
||||||
This option prints the names of the sixteen major
|
This option prints the names of the sixteen major
|
||||||
galactic regions referred to in the game.
|
galactic regions referred to in the game.
|
||||||
|
|
||||||
|
|||||||
1
84 Super Star Trek/csharp/Resources/LowShields.txt
Normal file
1
84 Super Star Trek/csharp/Resources/LowShields.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SHIELDS DANGEROUSLY LOW
|
||||||
6
84 Super Star Trek/csharp/Resources/Orders.txt
Normal file
6
84 Super Star Trek/csharp/Resources/Orders.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Your orders are as follows:
|
||||||
|
Destroy the {0} Klingon warships which have invaded
|
||||||
|
the galaxy before they can attack federation headquarters
|
||||||
|
on stardate {1}. This gives you {2} days. There {3}
|
||||||
|
{4} starbase{5} in the galaxy for resupplying your ship.
|
||||||
|
|
||||||
3
84 Super Star Trek/csharp/Resources/ReplayPrompt.txt
Normal file
3
84 Super Star Trek/csharp/Resources/ReplayPrompt.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
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'
|
||||||
1
84 Super Star Trek/csharp/Resources/ShieldsDropped.txt
Normal file
1
84 Super Star Trek/csharp/Resources/ShieldsDropped.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Shields dropped for docking purposes
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*** Short Range Sensors are out ***
|
||||||
5
84 Super Star Trek/csharp/Resources/StartText.txt
Normal file
5
84 Super Star Trek/csharp/Resources/StartText.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Your mission begins with your starship located
|
||||||
|
in the galactic quadrant, '{0}'.
|
||||||
|
|
||||||
@@ -2,15 +2,20 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
using static System.StringComparison;
|
namespace SuperStarTrek.Resources
|
||||||
|
|
||||||
namespace SuperStarTrek
|
|
||||||
{
|
{
|
||||||
internal static class Strings
|
internal static class Strings
|
||||||
{
|
{
|
||||||
public static string Title => GetResource();
|
public static string CombatArea => GetResource();
|
||||||
public static string Instructions => GetResource();
|
|
||||||
public static string Enterprise => GetResource();
|
public static string Enterprise => GetResource();
|
||||||
|
public static string Instructions => GetResource();
|
||||||
|
public static string LowShields => GetResource();
|
||||||
|
public static string Orders => GetResource();
|
||||||
|
public static string ReplayPrompt => GetResource();
|
||||||
|
public static string ShieldsDropped => GetResource();
|
||||||
|
public static string ShortRangeSensorsOut => GetResource();
|
||||||
|
public static string StartText => GetResource();
|
||||||
|
public static string Title => GetResource();
|
||||||
|
|
||||||
private static string GetResource([CallerMemberName] string name = "")
|
private static string GetResource([CallerMemberName] string name = "")
|
||||||
{
|
{
|
||||||
27
84 Super Star Trek/csharp/Space/Coordinate.cs
Normal file
27
84 Super Star Trek/csharp/Space/Coordinate.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Space
|
||||||
|
{
|
||||||
|
// Represents the corrdintate of a quadrant in the galaxy, or a sector in a quadrant.
|
||||||
|
// Note that the origin is top-left, x increase downwards, and y increases to the right.
|
||||||
|
internal record Coordinates
|
||||||
|
{
|
||||||
|
public Coordinates(int x, int y)
|
||||||
|
{
|
||||||
|
X = Validated(x, nameof(x));
|
||||||
|
Y = Validated(y, nameof(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int X { get; }
|
||||||
|
public int Y { get; }
|
||||||
|
|
||||||
|
private int Validated(int value, string argumentName)
|
||||||
|
{
|
||||||
|
if (value >= 1 && value <= 8) { return value; }
|
||||||
|
|
||||||
|
throw new ArgumentOutOfRangeException(argumentName, value, "Must be 1 to 8 inclusive");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{X} , {Y}";
|
||||||
|
}
|
||||||
|
}
|
||||||
50
84 Super Star Trek/csharp/Space/Course.cs
Normal file
50
84 Super Star Trek/csharp/Space/Course.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Space
|
||||||
|
{
|
||||||
|
// Implements the course calculations from the original code:
|
||||||
|
// 530 FORI=1TO9:C(I,1)=0:C(I,2)=0:NEXTI
|
||||||
|
// 540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1
|
||||||
|
// 600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1
|
||||||
|
//
|
||||||
|
// 3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1))
|
||||||
|
// 3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1))
|
||||||
|
internal class Course
|
||||||
|
{
|
||||||
|
private static readonly (int DeltaX, int DeltaY)[] cardinals = new[]
|
||||||
|
{
|
||||||
|
(0, 1),
|
||||||
|
(-1, 1),
|
||||||
|
(-1, 0),
|
||||||
|
(-1, -1),
|
||||||
|
(0, -1),
|
||||||
|
(1, -1),
|
||||||
|
(1, 0),
|
||||||
|
(1, 1),
|
||||||
|
(0, 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
public Course(double direction)
|
||||||
|
{
|
||||||
|
if (direction < 1 || direction > 9)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(direction),
|
||||||
|
direction,
|
||||||
|
"Must be between 1 and 9, inclusive.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardinalDirection = (int)(direction - 1) % 8;
|
||||||
|
var fractionalDirection = direction - (int)direction;
|
||||||
|
|
||||||
|
var baseCardinal = cardinals[cardinalDirection];
|
||||||
|
var nextCardinal = cardinals[cardinalDirection + 1];
|
||||||
|
|
||||||
|
DeltaX = baseCardinal.DeltaX + (nextCardinal.DeltaX - baseCardinal.DeltaX) * fractionalDirection;
|
||||||
|
DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DeltaX { get; }
|
||||||
|
public double DeltaY { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
34
84 Super Star Trek/csharp/Space/Galaxy.cs
Normal file
34
84 Super Star Trek/csharp/Space/Galaxy.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Space
|
||||||
|
{
|
||||||
|
internal class Galaxy
|
||||||
|
{
|
||||||
|
private readonly QuadrantInfo[][] _quadrants;
|
||||||
|
|
||||||
|
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())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (StarbaseCount == 0)
|
||||||
|
{
|
||||||
|
var randomQuadrant = this[random.GetCoordinate()];
|
||||||
|
randomQuadrant.AddStarbase();
|
||||||
|
|
||||||
|
if (randomQuadrant.KlingonCount < 2)
|
||||||
|
{
|
||||||
|
randomQuadrant.AddKlingon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X - 1][coordinate.Y - 1];
|
||||||
|
|
||||||
|
public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount);
|
||||||
|
public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
84 Super Star Trek/csharp/Space/Quadrant.cs
Normal file
79
84 Super Star Trek/csharp/Space/Quadrant.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using SuperStarTrek.Objects;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Space
|
||||||
|
{
|
||||||
|
internal class Quadrant
|
||||||
|
{
|
||||||
|
private readonly QuadrantInfo _info;
|
||||||
|
private readonly Random _random;
|
||||||
|
private readonly Dictionary<Coordinates, object> _sectors;
|
||||||
|
private readonly Coordinates _enterpriseSector;
|
||||||
|
private readonly Coordinates _starbaseSector;
|
||||||
|
|
||||||
|
public Quadrant(QuadrantInfo info, Enterprise enterprise)
|
||||||
|
{
|
||||||
|
_info = info;
|
||||||
|
_random = new Random();
|
||||||
|
|
||||||
|
_enterpriseSector = enterprise.Sector;
|
||||||
|
_sectors = new Dictionary<Coordinates, object> { [enterprise.Sector] = enterprise };
|
||||||
|
PositionObject(() => new Klingon(), _info.KlingonCount);
|
||||||
|
if (_info.HasStarbase)
|
||||||
|
{
|
||||||
|
_starbaseSector = PositionObject(() => new Starbase());
|
||||||
|
}
|
||||||
|
PositionObject(() => new Star(), _info.StarCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinates Coordinates => _info.Coordinates;
|
||||||
|
public bool HasKlingons => _info.KlingonCount > 0;
|
||||||
|
public bool HasStarbase => _info.HasStarbase;
|
||||||
|
public bool EnterpriseIsNextToStarbase =>
|
||||||
|
_info.HasStarbase &&
|
||||||
|
Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 &&
|
||||||
|
Math.Abs(_enterpriseSector.Y - _starbaseSector.Y) <= 1;
|
||||||
|
|
||||||
|
public override string ToString() => _info.Name;
|
||||||
|
|
||||||
|
private Coordinates PositionObject(Func<object> objectFactory)
|
||||||
|
{
|
||||||
|
var sector = GetRandomEmptySector();
|
||||||
|
_sectors[sector] = objectFactory.Invoke();
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PositionObject(Func<object> objectFactory, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
PositionObject(objectFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Coordinates GetRandomEmptySector()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var sector = _random.GetCoordinate();
|
||||||
|
if (!_sectors.ContainsKey(sector))
|
||||||
|
{
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> GetDisplayLines() => Enumerable.Range(1, 8).Select(x => GetDisplayLine(x));
|
||||||
|
|
||||||
|
private string GetDisplayLine(int x)
|
||||||
|
=> string.Join(
|
||||||
|
" ",
|
||||||
|
Enumerable
|
||||||
|
.Range(1, 8)
|
||||||
|
.Select(y => new Coordinates(x, y))
|
||||||
|
.Select(c => _sectors.GetValueOrDefault(c))
|
||||||
|
.Select(o => o?.ToString() ?? " "));
|
||||||
|
}
|
||||||
|
}
|
||||||
40
84 Super Star Trek/csharp/Space/QuadrantInfo.cs
Normal file
40
84 Super Star Trek/csharp/Space/QuadrantInfo.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
namespace SuperStarTrek.Space
|
||||||
|
{
|
||||||
|
internal class QuadrantInfo
|
||||||
|
{
|
||||||
|
private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase)
|
||||||
|
{
|
||||||
|
Coordinates = coordinates;
|
||||||
|
Name = name;
|
||||||
|
KlingonCount = klingonCount;
|
||||||
|
StarCount = starCount;
|
||||||
|
HasStarbase = hasStarbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinates Coordinates { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public int KlingonCount { get; private set; }
|
||||||
|
public bool HasStarbase { get; private set; }
|
||||||
|
public int StarCount { get; }
|
||||||
|
|
||||||
|
public static QuadrantInfo Create(Coordinates coordinates, string name)
|
||||||
|
{
|
||||||
|
var random = new Random();
|
||||||
|
var klingonCount = random.GetDouble() switch
|
||||||
|
{
|
||||||
|
> 0.98 => 3,
|
||||||
|
> 0.95 => 2,
|
||||||
|
> 0.80 => 1,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
var hasStarbase = random.GetDouble() > 0.96;
|
||||||
|
var starCount = random.Get1To8Inclusive();
|
||||||
|
|
||||||
|
return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddKlingon() => KlingonCount += 1;
|
||||||
|
|
||||||
|
internal void AddStarbase() => HasStarbase = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
84 Super Star Trek/csharp/Systems/ShieldControl.cs
Normal file
53
84 Super Star Trek/csharp/Systems/ShieldControl.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using SuperStarTrek.Objects;
|
||||||
|
using SuperStarTrek.Space;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Systems
|
||||||
|
{
|
||||||
|
internal class ShieldControl : Subsystem
|
||||||
|
{
|
||||||
|
private readonly Enterprise _enterprise;
|
||||||
|
private readonly Output _output;
|
||||||
|
private readonly Input _input;
|
||||||
|
|
||||||
|
public ShieldControl(Enterprise enterprise, Output output, Input input)
|
||||||
|
: base("Shield Control", Command.SHE)
|
||||||
|
{
|
||||||
|
_enterprise = enterprise;
|
||||||
|
_output = output;
|
||||||
|
_input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Energy { get; private set; }
|
||||||
|
|
||||||
|
public override void ExecuteCommand(Quadrant quadrant)
|
||||||
|
{
|
||||||
|
if (Condition < 0)
|
||||||
|
{
|
||||||
|
_output.WriteLine("Shield Control inoperable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine($"Energy available = {_enterprise.TotalEnergy}");
|
||||||
|
var requested = _input.GetNumber($"Number of units to shields");
|
||||||
|
|
||||||
|
if (Validate(requested))
|
||||||
|
{
|
||||||
|
Energy = requested;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine("<SHIELDS UNCHANGED>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Validate(double requested)
|
||||||
|
{
|
||||||
|
if (requested > _enterprise.TotalEnergy)
|
||||||
|
{
|
||||||
|
_output.WriteLine("Shield Control reports, 'This is not the Federation Treasury.'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return requested >= 0 && requested != Energy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs
Normal file
59
84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using SuperStarTrek.Objects;
|
||||||
|
using SuperStarTrek.Resources;
|
||||||
|
using SuperStarTrek.Space;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Systems
|
||||||
|
{
|
||||||
|
internal class ShortRangeSensors : Subsystem
|
||||||
|
{
|
||||||
|
private readonly Enterprise _enterprise;
|
||||||
|
private readonly Galaxy _galaxy;
|
||||||
|
private readonly Game _game;
|
||||||
|
private readonly Output _output;
|
||||||
|
|
||||||
|
public ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output)
|
||||||
|
: base("Short Range Sensors", Command.SRS)
|
||||||
|
{
|
||||||
|
_enterprise = enterprise;
|
||||||
|
_galaxy = galaxy;
|
||||||
|
_game = game;
|
||||||
|
_output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExecuteCommand(Quadrant quadrant)
|
||||||
|
{
|
||||||
|
if (_enterprise.IsDocked)
|
||||||
|
{
|
||||||
|
_output.WriteLine(Strings.ShieldsDropped);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Condition < 0)
|
||||||
|
{
|
||||||
|
_output.WriteLine(Strings.ShortRangeSensorsOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine("---------------------------------");
|
||||||
|
quadrant.GetDisplayLines()
|
||||||
|
.Zip(GetStatusLines(), (sectors, status) => $" {sectors} {status}")
|
||||||
|
.ToList()
|
||||||
|
.ForEach(l => _output.WriteLine(l));
|
||||||
|
_output.WriteLine("---------------------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> GetStatusLines()
|
||||||
|
{
|
||||||
|
yield return $"Stardate {_game.Stardate}";
|
||||||
|
yield return $"Condition {_enterprise.Condition}";
|
||||||
|
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 $"Klingons remaining {_galaxy.KlingonCount}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
84 Super Star Trek/csharp/Systems/Subsystem.cs
Normal file
20
84 Super Star Trek/csharp/Systems/Subsystem.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using SuperStarTrek.Space;
|
||||||
|
|
||||||
|
namespace SuperStarTrek.Systems
|
||||||
|
{
|
||||||
|
internal abstract class Subsystem
|
||||||
|
{
|
||||||
|
protected Subsystem(string name, Command command)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Command = command;
|
||||||
|
Condition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public double Condition { get; }
|
||||||
|
public Command Command { get; }
|
||||||
|
|
||||||
|
public abstract void ExecuteCommand(Quadrant quadrant);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user