AdventOfCode2018: Move tests to the corresponding day

This commit is contained in:
2023-12-03 03:07:00 +01:00
parent fd09931145
commit b36594f391
17 changed files with 837 additions and 850 deletions

View File

@@ -175,100 +175,100 @@ public class Day04 : IDay
return dictFullHistogram;
}
}
public enum GuardEventType
{
ShiftBegin,
FallSleep,
WakeUp,
}
public class GuardEvent
{
public DateTime Date { get; set; }
public int? ID { get; set; }
public GuardEventType Type { get; set; }
public static GuardEvent FromString(string strEvent)
public enum GuardEventType
{
GuardEvent guardEvent = new();
string[] parts = strEvent.Split(new[] { "[", "-", " ", ":", "]", "#", }, StringSplitOptions.RemoveEmptyEntries);
guardEvent.Date = new DateTime(
Convert.ToInt32(parts[0]),
Convert.ToInt32(parts[1]),
Convert.ToInt32(parts[2]),
Convert.ToInt32(parts[3]),
Convert.ToInt32(parts[4]),
0
);
if (parts[5] == "Guard")
{
guardEvent.ID = Convert.ToInt32(parts[6]);
guardEvent.Type = GuardEventType.ShiftBegin;
}
if (parts[5] == "falls")
{
guardEvent.Type = GuardEventType.FallSleep;
}
if (parts[5] == "wakes")
{
guardEvent.Type = GuardEventType.WakeUp;
}
return guardEvent;
ShiftBegin,
FallSleep,
WakeUp,
}
public static List<GuardEvent> FromStringArray(string[] strEvents)
public class GuardEvent
{
List<GuardEvent> guardEvents = strEvents
.Select(strEvent => FromString(strEvent))
.OrderBy(guardEvent => guardEvent.Date)
.ToList();
public DateTime Date { get; set; }
public int? ID { get; set; }
public GuardEventType Type { get; set; }
int? guardID = null;
foreach (GuardEvent guardEvent in guardEvents)
public static GuardEvent FromString(string strEvent)
{
if (guardEvent.Type == GuardEventType.ShiftBegin)
GuardEvent guardEvent = new();
string[] parts = strEvent.Split(new[] { "[", "-", " ", ":", "]", "#", }, StringSplitOptions.RemoveEmptyEntries);
guardEvent.Date = new DateTime(
Convert.ToInt32(parts[0]),
Convert.ToInt32(parts[1]),
Convert.ToInt32(parts[2]),
Convert.ToInt32(parts[3]),
Convert.ToInt32(parts[4]),
0
);
if (parts[5] == "Guard")
{
guardID = guardEvent.ID;
guardEvent.ID = Convert.ToInt32(parts[6]);
guardEvent.Type = GuardEventType.ShiftBegin;
}
else
if (parts[5] == "falls")
{
guardEvent.ID = guardID;
guardEvent.Type = GuardEventType.FallSleep;
}
if (parts[5] == "wakes")
{
guardEvent.Type = GuardEventType.WakeUp;
}
return guardEvent;
}
public static List<GuardEvent> FromStringArray(string[] strEvents)
{
List<GuardEvent> guardEvents = strEvents
.Select(strEvent => FromString(strEvent))
.OrderBy(guardEvent => guardEvent.Date)
.ToList();
int? guardID = null;
foreach (GuardEvent guardEvent in guardEvents)
{
if (guardEvent.Type == GuardEventType.ShiftBegin)
{
guardID = guardEvent.ID;
}
else
{
guardEvent.ID = guardID;
}
}
return guardEvents;
}
}
public class GuardSleepHistogram
{
public const int MinutesOnHour = 60;
public int ID { get; set; }
public int[] SleepOnMunute { get; } = new int[MinutesOnHour];
public void FallSleep(int minute)
{
for (int i = minute; i < MinutesOnHour; i++)
{
SleepOnMunute[i] = 1;
}
}
return guardEvents;
}
}
public class GuardSleepHistogram
{
public const int MinutesOnHour = 60;
public int ID { get; set; }
public int[] SleepOnMunute { get; } = new int[MinutesOnHour];
public void FallSleep(int minute)
{
for (int i = minute; i < MinutesOnHour; i++)
public void WakeUp(int minute)
{
SleepOnMunute[i] = 1;
for (int i = minute; i < MinutesOnHour; i++)
{
SleepOnMunute[i] = 0;
}
}
}
public void WakeUp(int minute)
{
for (int i = minute; i < MinutesOnHour; i++)
public void AddHistogram(GuardSleepHistogram histogram)
{
SleepOnMunute[i] = 0;
}
}
public void AddHistogram(GuardSleepHistogram histogram)
{
for (int i = 0; i < MinutesOnHour; i++)
{
SleepOnMunute[i] += histogram.SleepOnMunute[i];
for (int i = 0; i < MinutesOnHour; i++)
{
SleepOnMunute[i] += histogram.SleepOnMunute[i];
}
}
}
}

View File

@@ -112,16 +112,16 @@ public class Day06 : IDay
{
pointsAreas.Add(i, 0);
}
int minX = points.Min(p => p.X) - 1;
int maxX = points.Max(p => p.X) + 1;
int minY = points.Min(p => p.Y) - 1;
int maxY = points.Max(p => p.Y) + 1;
ChronoPoint samplingPoint = new();
for(int i=minX; i <= maxX; i++)
for (int i = minX; i <= maxX; i++)
{
for(int j = minY; j <= maxY; j++)
for (int j = minY; j <= maxY; j++)
{
samplingPoint.X = i;
samplingPoint.Y = j;
@@ -195,28 +195,28 @@ public class Day06 : IDay
int areaInRange = AreaInThresold(points, DistanceThresold);
return areaInRange.ToString();
}
}
public class ChronoPoint
{
public int X { get; set; }
public int Y { get; set; }
public static ChronoPoint FromString(string strPoint)
public class ChronoPoint
{
if (string.IsNullOrEmpty(strPoint)) { return null; }
string[] parts = strPoint.Split(new[] { ", ", }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2) { return null; }
ChronoPoint point = new() {
X = Convert.ToInt32(parts[0]),
Y = Convert.ToInt32(parts[1]),
};
return point;
}
public int X { get; set; }
public int Y { get; set; }
public static int ManhattanDistance(ChronoPoint p0, ChronoPoint p1)
{
int distance = Math.Abs(p1.X - p0.X) + Math.Abs(p1.Y - p0.Y);
return distance;
public static ChronoPoint FromString(string strPoint)
{
if (string.IsNullOrEmpty(strPoint)) { return null; }
string[] parts = strPoint.Split(new[] { ", ", }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2) { return null; }
ChronoPoint point = new() {
X = Convert.ToInt32(parts[0]),
Y = Convert.ToInt32(parts[1]),
};
return point;
}
public static int ManhattanDistance(ChronoPoint p0, ChronoPoint p1)
{
int distance = Math.Abs(p1.X - p0.X) + Math.Abs(p1.Y - p0.Y);
return distance;
}
}
}

View File

@@ -130,154 +130,154 @@ public class Day07 : IDay
int totalElapsedTime = instructions.SimulateInstructionsUsage(NumberOfWorkers);
return totalElapsedTime.ToString();
}
}
public class InstructionNode
{
public string NodeID { get; set; }
public List<string> PreviousNodeIDs { get; } = new();
public int Cost { get; set; }
public bool Running { get; set; }
public bool Used { get; set; }
public bool CanBeUsed(Dictionary<string, InstructionNode> allNodes)
public class InstructionNode
{
if (PreviousNodeIDs.Count == 0) { return true; }
bool allPreviousUsed = PreviousNodeIDs.All(nodeID => allNodes[nodeID].Used);
return allPreviousUsed;
}
}
public string NodeID { get; set; }
public class Instructions
{
public Dictionary<string, InstructionNode> Nodes { get; } = new();
public List<string> PreviousNodeIDs { get; } = new();
public InstructionNode GetNode(string nodeID)
{
InstructionNode node = null;
if (Nodes.ContainsKey(nodeID))
public int Cost { get; set; }
public bool Running { get; set; }
public bool Used { get; set; }
public bool CanBeUsed(Dictionary<string, InstructionNode> allNodes)
{
node = Nodes[nodeID];
if (PreviousNodeIDs.Count == 0) { return true; }
bool allPreviousUsed = PreviousNodeIDs.All(nodeID => allNodes[nodeID].Used);
return allPreviousUsed;
}
else
{
node = new InstructionNode { NodeID = nodeID, };
Nodes.Add(nodeID, node);
}
return node;
}
public void AddNodeRelation(string nodeID, string previousNodeID)
public class Instructions
{
InstructionNode node = GetNode(nodeID);
InstructionNode previousNode = GetNode(previousNodeID);
node.PreviousNodeIDs.Add(previousNode.NodeID);
}
public Dictionary<string, InstructionNode> Nodes { get; } = new();
public List<InstructionNode> SortInstructions()
{
List<InstructionNode> finalNodes = new();
foreach (InstructionNode node in Nodes.Values)
public InstructionNode GetNode(string nodeID)
{
node.Used = false;
}
List<InstructionNode> unusedNodes;
do
{
unusedNodes = Nodes.Values
.Where(n =>
n.Used == false &&
n.CanBeUsed(Nodes))
.OrderBy(n => n.NodeID)
.ToList();
if (unusedNodes.Count > 0)
InstructionNode node = null;
if (Nodes.ContainsKey(nodeID))
{
InstructionNode node = unusedNodes.FirstOrDefault();
finalNodes.Add(node);
node.Used = true;
node = Nodes[nodeID];
}
} while (unusedNodes.Count > 0);
return finalNodes;
}
private class SimulatedWorker
{
public InstructionNode CurrentInstruction { get; set; }
public int ElapsedTime { get; set; }
public void SetInstruction(InstructionNode instruction)
{
CurrentInstruction = instruction;
ElapsedTime = 0;
instruction.Running = true;
}
public bool Work()
{
if (CurrentInstruction == null) { return false; }
ElapsedTime++;
if (CurrentInstruction.Cost <= ElapsedTime)
else
{
CurrentInstruction.Running = false;
CurrentInstruction.Used = true;
CurrentInstruction = null;
node = new InstructionNode { NodeID = nodeID, };
Nodes.Add(nodeID, node);
}
return true;
}
}
public int SimulateInstructionsUsage(int numberOfWorkers)
{
int totalElapsedTime = 0;
foreach (InstructionNode node in Nodes.Values)
{
node.Used = false;
node.Running = false;
}
List<SimulatedWorker> workers = new(numberOfWorkers);
for (int i = 0; i < numberOfWorkers; i++)
{
workers.Add(new SimulatedWorker());
return node;
}
bool anyWorkerWitoutWork;
do
public void AddNodeRelation(string nodeID, string previousNodeID)
{
bool anyWorkDone = false;
foreach (SimulatedWorker worker in workers)
InstructionNode node = GetNode(nodeID);
InstructionNode previousNode = GetNode(previousNodeID);
node.PreviousNodeIDs.Add(previousNode.NodeID);
}
public List<InstructionNode> SortInstructions()
{
List<InstructionNode> finalNodes = new();
foreach (InstructionNode node in Nodes.Values)
{
if (worker.Work())
{
anyWorkDone = true;
}
node.Used = false;
}
if (anyWorkDone) { totalElapsedTime++; }
anyWorkerWitoutWork = workers.Any(w => w.CurrentInstruction == null);
if (anyWorkerWitoutWork)
List<InstructionNode> unusedNodes;
do
{
List<InstructionNode> unusedNodes = Nodes.Values
unusedNodes = Nodes.Values
.Where(n =>
n.Used == false && n.Running == false &&
n.Used == false &&
n.CanBeUsed(Nodes))
.OrderBy(n => n.NodeID)
.ToList();
if (unusedNodes.Count > 0)
{
List<SimulatedWorker> workersWithoutWork = workers.Where(w => w.CurrentInstruction == null).ToList();
for (int i = 0; i < workersWithoutWork.Count && i < unusedNodes.Count; i++)
InstructionNode node = unusedNodes.FirstOrDefault();
finalNodes.Add(node);
node.Used = true;
}
} while (unusedNodes.Count > 0);
return finalNodes;
}
private class SimulatedWorker
{
public InstructionNode CurrentInstruction { get; set; }
public int ElapsedTime { get; set; }
public void SetInstruction(InstructionNode instruction)
{
CurrentInstruction = instruction;
ElapsedTime = 0;
instruction.Running = true;
}
public bool Work()
{
if (CurrentInstruction == null) { return false; }
ElapsedTime++;
if (CurrentInstruction.Cost <= ElapsedTime)
{
CurrentInstruction.Running = false;
CurrentInstruction.Used = true;
CurrentInstruction = null;
}
return true;
}
}
public int SimulateInstructionsUsage(int numberOfWorkers)
{
int totalElapsedTime = 0;
foreach (InstructionNode node in Nodes.Values)
{
node.Used = false;
node.Running = false;
}
List<SimulatedWorker> workers = new(numberOfWorkers);
for (int i = 0; i < numberOfWorkers; i++)
{
workers.Add(new SimulatedWorker());
}
bool anyWorkerWitoutWork;
do
{
bool anyWorkDone = false;
foreach (SimulatedWorker worker in workers)
{
if (worker.Work())
{
workersWithoutWork[i].SetInstruction(unusedNodes[i]);
anyWorkDone = true;
}
}
}
} while (workers.Any(w => w.CurrentInstruction != null));
return totalElapsedTime;
if (anyWorkDone) { totalElapsedTime++; }
anyWorkerWitoutWork = workers.Any(w => w.CurrentInstruction == null);
if (anyWorkerWitoutWork)
{
List<InstructionNode> unusedNodes = Nodes.Values
.Where(n =>
n.Used == false && n.Running == false &&
n.CanBeUsed(Nodes))
.OrderBy(n => n.NodeID)
.ToList();
if (unusedNodes.Count > 0)
{
List<SimulatedWorker> workersWithoutWork = workers.Where(w => w.CurrentInstruction == null).ToList();
for (int i = 0; i < workersWithoutWork.Count && i < unusedNodes.Count; i++)
{
workersWithoutWork[i].SetInstruction(unusedNodes[i]);
}
}
}
} while (workers.Any(w => w.CurrentInstruction != null));
return totalElapsedTime;
}
}
}

View File

@@ -78,82 +78,82 @@ public class Day08 : IDay
int result = licenceTree.GetValue();
return result.ToString();
}
}
public class IntStream
{
private int[] _values;
private int _index;
public IntStream(string strValues)
public class IntStream
{
_values = strValues
.Split(new[] { " ", }, StringSplitOptions.RemoveEmptyEntries)
.Select(strVal => Convert.ToInt32(strVal))
.ToArray();
_index = 0;
}
private int[] _values;
private int _index;
public int Get()
{
int value = _values[_index];
_index++;
return value;
}
}
public class ChronoLicenceNode
{
public List<ChronoLicenceNode> Childs { get; } = new();
public List<int> Metadata { get; } = new();
public static ChronoLicenceNode BuildFromIntStream(IntStream stream)
{
ChronoLicenceNode node = new();
int numChilds = stream.Get();
int numMetadata = stream.Get();
for (int i = 0; i < numChilds; i++)
public IntStream(string strValues)
{
ChronoLicenceNode childNode = BuildFromIntStream(stream);
node.Childs.Add(childNode);
_values = strValues
.Split(new[] { " ", }, StringSplitOptions.RemoveEmptyEntries)
.Select(strVal => Convert.ToInt32(strVal))
.ToArray();
_index = 0;
}
for (int i = 0; i < numMetadata; i++)
public int Get()
{
node.Metadata.Add(stream.Get());
int value = _values[_index];
_index++;
return value;
}
return node;
}
public int GetChecksum()
public class ChronoLicenceNode
{
int checksum = Metadata.Sum();
foreach (ChronoLicenceNode child in Childs)
{
checksum += child.GetChecksum();
}
return checksum;
}
public List<ChronoLicenceNode> Childs { get; } = new();
public int GetValue()
{
int value = 0;
if (Childs.Count == 0)
public List<int> Metadata { get; } = new();
public static ChronoLicenceNode BuildFromIntStream(IntStream stream)
{
value = Metadata.Sum();
}
else
{
foreach (int metadata in Metadata)
ChronoLicenceNode node = new();
int numChilds = stream.Get();
int numMetadata = stream.Get();
for (int i = 0; i < numChilds; i++)
{
int index = metadata - 1;
if (index < 0 || index >= Childs.Count) { continue; }
value += Childs[index].GetValue();
ChronoLicenceNode childNode = BuildFromIntStream(stream);
node.Childs.Add(childNode);
}
for (int i = 0; i < numMetadata; i++)
{
node.Metadata.Add(stream.Get());
}
return node;
}
public int GetChecksum()
{
int checksum = Metadata.Sum();
foreach (ChronoLicenceNode child in Childs)
{
checksum += child.GetChecksum();
}
return checksum;
}
public int GetValue()
{
int value = 0;
if (Childs.Count == 0)
{
value = Metadata.Sum();
}
else
{
foreach (int metadata in Metadata)
{
int index = metadata - 1;
if (index < 0 || index >= Childs.Count) { continue; }
value += Childs[index].GetValue();
}
}
return value;
}
return value;
}
}

View File

@@ -87,86 +87,86 @@ public class Day09 : IDay
long result = marbleGame.GetHighScore();
return result.ToString();
}
}
public class Marble
{
public long Value { get; set; }
public Marble Previous { get; set; }
public Marble Next { get; set; }
}
public class MarbleGame
{
public Dictionary<long, long> Scores { get; } = new();
private Marble _firstMarble;
private Marble _currentMarble;
private long _currentPlayer;
private const long PointValueMultiple = 23;
public void PlayGame(long numPlayers, long lastMarble, bool showStatus = false)
public class Marble
{
Scores.Clear();
_firstMarble = new Marble { Value = 0 };
_firstMarble.Previous = _firstMarble;
_firstMarble.Next = _firstMarble;
_currentMarble = _firstMarble;
public long Value { get; set; }
public Marble Previous { get; set; }
public Marble Next { get; set; }
}
for (long i = 1; i <= numPlayers; i++) { Scores.Add(i, 0); }
public class MarbleGame
{
public Dictionary<long, long> Scores { get; } = new();
for (long i = 0; i <= lastMarble; i++)
private Marble _firstMarble;
private Marble _currentMarble;
private long _currentPlayer;
private const long PointValueMultiple = 23;
public void PlayGame(long numPlayers, long lastMarble, bool showStatus = false)
{
if (showStatus) { PrintStatus(); }
Scores.Clear();
_firstMarble = new Marble { Value = 0 };
_firstMarble.Previous = _firstMarble;
_firstMarble.Next = _firstMarble;
_currentMarble = _firstMarble;
_currentPlayer = (i % numPlayers) + 1;
Marble newMarble = new() { Value = i + 1 };
if ((newMarble.Value % PointValueMultiple) > 0)
for (long i = 1; i <= numPlayers; i++) { Scores.Add(i, 0); }
for (long i = 0; i <= lastMarble; i++)
{
Marble previousMarble = _currentMarble.Next;
Marble nextMarble = previousMarble.Next;
newMarble.Previous = previousMarble;
newMarble.Next = nextMarble;
previousMarble.Next = newMarble;
nextMarble.Previous = newMarble;
_currentMarble = newMarble;
if (showStatus) { PrintStatus(); }
_currentPlayer = (i % numPlayers) + 1;
Marble newMarble = new() { Value = i + 1 };
if ((newMarble.Value % PointValueMultiple) > 0)
{
Marble previousMarble = _currentMarble.Next;
Marble nextMarble = previousMarble.Next;
newMarble.Previous = previousMarble;
newMarble.Next = nextMarble;
previousMarble.Next = newMarble;
nextMarble.Previous = newMarble;
_currentMarble = newMarble;
}
else
{
Marble marbleToRemove = _currentMarble.Previous.Previous.Previous.Previous.Previous.Previous.Previous;
_currentMarble = marbleToRemove.Next;
marbleToRemove.Previous.Next = marbleToRemove.Next;
marbleToRemove.Next.Previous = marbleToRemove.Previous;
long currentPlayerScore = Scores[_currentPlayer] + (newMarble.Value + marbleToRemove.Value);
Scores[_currentPlayer] = currentPlayerScore;
}
}
else
}
public void PrintStatus()
{
Console.Write("[{0}] ", _currentPlayer);
Marble marble = _firstMarble;
do
{
Marble marbleToRemove = _currentMarble.Previous.Previous.Previous.Previous.Previous.Previous.Previous;
_currentMarble = marbleToRemove.Next;
marbleToRemove.Previous.Next = marbleToRemove.Next;
marbleToRemove.Next.Previous = marbleToRemove.Previous;
long currentPlayerScore = Scores[_currentPlayer] + (newMarble.Value + marbleToRemove.Value);
Scores[_currentPlayer] = currentPlayerScore;
}
if (_currentMarble.Value == marble.Value)
{
Console.Write("({0}) ", marble.Value);
}
else
{
Console.Write("{0} ", marble.Value);
}
marble = marble.Next;
} while (marble.Value != 0);
Console.WriteLine();
}
public long GetHighScore()
{
return Scores.Values.Max();
}
}
public void PrintStatus()
{
Console.Write("[{0}] ", _currentPlayer);
Marble marble = _firstMarble;
do
{
if (_currentMarble.Value == marble.Value)
{
Console.Write("({0}) ", marble.Value);
}
else
{
Console.Write("{0} ", marble.Value);
}
marble = marble.Next;
} while (marble.Value != 0);
Console.WriteLine();
}
public long GetHighScore()
{
return Scores.Values.Max();
}
}

View File

@@ -176,132 +176,132 @@ public class Day10 : IDay
int t = lightField.SearchSmallerBoundindBox();
return t.ToString();
}
}
public class LightPoint
{
public int X { get; set; }
public int Y { get; set; }
public int VX { get; set; }
public int VY { get; set; }
public static LightPoint FromString(string strPoint)
public class LightPoint
{
string[] parts = strPoint.Split(new[] { "position=<", " ", ",", "> velocity=<", ">" }, StringSplitOptions.RemoveEmptyEntries);
LightPoint point = new() {
X = Convert.ToInt32(parts[0]),
Y = Convert.ToInt32(parts[1]),
VX = Convert.ToInt32(parts[2]),
VY = Convert.ToInt32(parts[3]),
};
return point;
}
public int X { get; set; }
public int Y { get; set; }
public int VX { get; set; }
public int VY { get; set; }
public int GetX(int t)
{
return X + (VX * t);
}
public int GetY(int t)
{
return Y + (VY * t);
}
}
public class LightField
{
private readonly List<LightPoint> _points;
public LightField(string[] strPoints)
{
_points = strPoints.Select(strPoint => LightPoint.FromString(strPoint)).ToList();
}
public int SearchSmallerBoundindBox()
{
int minHeight = int.MaxValue;
int minT = 0;
int missCount = 0;
int t = 0;
do
public static LightPoint FromString(string strPoint)
{
int minY = int.MaxValue;
int maxY = int.MinValue;
foreach (LightPoint point in _points)
{
int y = point.GetY(t);
if (y < minY) { minY = y; }
if (y > maxY) { maxY = y; }
}
int height = (maxY - minY);
if (height < minHeight)
{
minHeight = height;
minT = t;
missCount = 0;
}
else
{
missCount++;
}
t++;
} while (missCount < 1000);
return minT;
}
public string Render(int t, int width, int height)
{
int minX = int.MaxValue;
int minY = int.MaxValue;
int maxX = int.MinValue;
int maxY = int.MinValue;
foreach (LightPoint point in _points)
{
int x = point.GetX(t);
int y = point.GetY(t);
if (x < minX) { minX = x; }
if (y < minY) { minY = y; }
if (x > maxX) { maxX = x; }
if (y > maxY) { maxY = y; }
}
minX--;
minY--;
maxX += 2;
maxY += 2;
double scaleX = (maxX - minX) / (double)width;
double scaleY = (maxY - minY) / (double)height;
int[,] field = new int[width, height];
foreach (LightPoint point in _points)
{
int x = point.GetX(t);
int y = point.GetY(t);
x = (int)(((x - minX) / scaleX) + 0.5);
y = (int)(((y - minY) / scaleY) + 0.5);
if (x < 0 || x >= width) { continue; }
if (y < 0 || y >= height) { continue; }
field[x, y]++;
string[] parts = strPoint.Split(new[] { "position=<", " ", ",", "> velocity=<", ">" }, StringSplitOptions.RemoveEmptyEntries);
LightPoint point = new() {
X = Convert.ToInt32(parts[0]),
Y = Convert.ToInt32(parts[1]),
VX = Convert.ToInt32(parts[2]),
VY = Convert.ToInt32(parts[3]),
};
return point;
}
StringBuilder sb = new();
for (int j = 0; j < height; j++)
public int GetX(int t)
{
sb.AppendLine();
for (int i = 0; i < width; i++)
return X + (VX * t);
}
public int GetY(int t)
{
return Y + (VY * t);
}
}
public class LightField
{
private readonly List<LightPoint> _points;
public LightField(string[] strPoints)
{
_points = strPoints.Select(strPoint => LightPoint.FromString(strPoint)).ToList();
}
public int SearchSmallerBoundindBox()
{
int minHeight = int.MaxValue;
int minT = 0;
int missCount = 0;
int t = 0;
do
{
if (field[i, j] > 0)
int minY = int.MaxValue;
int maxY = int.MinValue;
foreach (LightPoint point in _points)
{
sb.Append("#");
int y = point.GetY(t);
if (y < minY) { minY = y; }
if (y > maxY) { maxY = y; }
}
int height = (maxY - minY);
if (height < minHeight)
{
minHeight = height;
minT = t;
missCount = 0;
}
else
{
sb.Append(".");
missCount++;
}
t++;
} while (missCount < 1000);
return minT;
}
public string Render(int t, int width, int height)
{
int minX = int.MaxValue;
int minY = int.MaxValue;
int maxX = int.MinValue;
int maxY = int.MinValue;
foreach (LightPoint point in _points)
{
int x = point.GetX(t);
int y = point.GetY(t);
if (x < minX) { minX = x; }
if (y < minY) { minY = y; }
if (x > maxX) { maxX = x; }
if (y > maxY) { maxY = y; }
}
minX--;
minY--;
maxX += 2;
maxY += 2;
double scaleX = (maxX - minX) / (double)width;
double scaleY = (maxY - minY) / (double)height;
int[,] field = new int[width, height];
foreach (LightPoint point in _points)
{
int x = point.GetX(t);
int y = point.GetY(t);
x = (int)(((x - minX) / scaleX) + 0.5);
y = (int)(((y - minY) / scaleY) + 0.5);
if (x < 0 || x >= width) { continue; }
if (y < 0 || y >= height) { continue; }
field[x, y]++;
}
StringBuilder sb = new();
for (int j = 0; j < height; j++)
{
sb.AppendLine();
for (int i = 0; i < width; i++)
{
if (field[i, j] > 0)
{
sb.Append("#");
}
else
{
sb.Append(".");
}
}
}
return sb.ToString();
}
return sb.ToString();
}
}