AdventOfCode2018: Move tests to the corresponding day
This commit is contained in:
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user