Files
basic-computer-games/84_Super_Star_Trek/csharp/Space/Quadrant.cs
2022-03-22 17:55:44 +11:00

193 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Games.Common.IO;
using Games.Common.Randomness;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
namespace SuperStarTrek.Space;
internal class Quadrant
{
private readonly QuadrantInfo _info;
private readonly IRandom _random;
private readonly Dictionary<Coordinates, object> _sectors;
private readonly Enterprise _enterprise;
private readonly IReadWrite _io;
private bool _entered = false;
internal Quadrant(
QuadrantInfo info,
Enterprise enterprise,
IRandom random,
Galaxy galaxy,
IReadWrite io)
{
_info = info;
_random = random;
_io = io;
Galaxy = galaxy;
info.MarkAsKnown();
_sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise };
PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount);
if (_info.HasStarbase)
{
Starbase = PositionObject(sector => new Starbase(sector, _random, io));
}
PositionObject(_ => new Star(), _info.StarCount);
}
internal Coordinates Coordinates => _info.Coordinates;
internal bool HasKlingons => _info.KlingonCount > 0;
internal int KlingonCount => _info.KlingonCount;
internal bool HasStarbase => _info.HasStarbase;
internal Starbase Starbase { get; }
internal Galaxy Galaxy { get; }
internal bool EnterpriseIsNextToStarbase =>
_info.HasStarbase &&
Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 &&
Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1;
internal IEnumerable<Klingon> Klingons => _sectors.Values.OfType<Klingon>();
public override string ToString() => _info.Name;
private T PositionObject<T>(Func<Coordinates, T> objectFactory)
{
var sector = GetRandomEmptySector();
_sectors[sector] = objectFactory.Invoke(sector);
return (T)_sectors[sector];
}
private void PositionObject(Func<Coordinates, object> objectFactory, int count)
{
for (int i = 0; i < count; i++)
{
PositionObject(objectFactory);
}
}
internal void Display(string textFormat)
{
if (!_entered)
{
_io.Write(textFormat, this);
_entered = true;
}
if (_info.KlingonCount > 0)
{
_io.Write(Strings.CombatArea);
if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _io.Write(Strings.LowShields); }
}
_enterprise.Execute(Command.SRS);
}
internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates);
internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver)
{
gameOver = false;
message = default;
switch (_sectors.GetValueOrDefault(coordinates))
{
case Klingon klingon:
message = Remove(klingon);
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 string Remove(Klingon klingon)
{
_sectors.Remove(klingon.Sector);
_info.RemoveKlingon();
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())
{
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)
{
var sector = _random.NextCoordinate();
if (!_sectors.ContainsKey(sector))
{
return sector;
}
}
}
internal IEnumerable<string> GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x));
private string GetDisplayLine(int x) =>
string.Join(
" ",
Enumerable
.Range(0, 8)
.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;
}
}