Initial Commit
This commit is contained in:
427
2022/Day16CSharp/Program.cs
Normal file
427
2022/Day16CSharp/Program.cs
Normal file
@@ -0,0 +1,427 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
|
||||
Part01();
|
||||
|
||||
void Part01()
|
||||
{
|
||||
Console.WriteLine("!! === Part 01 === !!");
|
||||
|
||||
Console.WriteLine("=== Example ===");
|
||||
var exampleData = new VolcanoData("example-input.txt");
|
||||
Console.WriteLine("Most Pressure Released: {0}", exampleData.GetMostPossiblePressureReleased(31));
|
||||
|
||||
Console.WriteLine("=== Puzzle ===");
|
||||
var puzzleData = new VolcanoData("puzzle-input.txt");
|
||||
Console.WriteLine("Most Pressure Released: {0}", puzzleData.GetMostPossiblePressureReleased(31));
|
||||
}
|
||||
|
||||
class StepList
|
||||
: IComparable
|
||||
{
|
||||
public struct Step
|
||||
{
|
||||
public enum StepType
|
||||
{
|
||||
First,
|
||||
Move,
|
||||
Open
|
||||
}
|
||||
|
||||
public StepType Type { get; set; }
|
||||
public Tuple<string,string> Value { get; set; }
|
||||
|
||||
public Step()
|
||||
{
|
||||
Type = StepType.First;
|
||||
Value = new Tuple<string, string>("AA", "0");
|
||||
}
|
||||
|
||||
public Step(string sourceValve, string targetValve)
|
||||
{
|
||||
Type = StepType.Move;
|
||||
Value = new Tuple<string, string>(sourceValve, targetValve);
|
||||
}
|
||||
|
||||
public Step(string valvename, int stepNumber)
|
||||
{
|
||||
Type = StepType.Open;
|
||||
Value = new Tuple<string, string>(valvename, stepNumber.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<Step> Steps { get; }
|
||||
private Dictionary<string, bool> OpenedValves { get; }
|
||||
|
||||
private IReadOnlyDictionary<string, Valve> Valves { get; }
|
||||
|
||||
public bool isValveOpen(string valveName)
|
||||
{
|
||||
return OpenedValves.ContainsKey(valveName);
|
||||
}
|
||||
|
||||
public StepList(IReadOnlyDictionary<string, Valve> valves, int maxSteps = 31)
|
||||
{
|
||||
MaxSteps = maxSteps;
|
||||
Valves = valves;
|
||||
|
||||
OpenedValves = new Dictionary<string, bool>();
|
||||
Steps = new List<Step>();
|
||||
}
|
||||
|
||||
public StepList(StepList other)
|
||||
{
|
||||
MaxSteps = other.MaxSteps;
|
||||
Valves = other.Valves;
|
||||
|
||||
OpenedValves = new Dictionary<string, bool>();
|
||||
Steps = new List<Step>();
|
||||
|
||||
foreach (var item in other.OpenedValves)
|
||||
{
|
||||
OpenedValves[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
foreach (var item in other.Steps)
|
||||
{
|
||||
Steps.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxSteps { get; }
|
||||
|
||||
public int StepCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return Steps.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanContinue
|
||||
{
|
||||
get
|
||||
{
|
||||
return StepCount < MaxSteps;
|
||||
}
|
||||
}
|
||||
|
||||
public Step Latest
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Steps.Count == 0) return new Step();
|
||||
return Steps[Steps.Count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddStep(Step step)
|
||||
{
|
||||
if (StepCount < MaxSteps)
|
||||
{
|
||||
Steps.Add(step);
|
||||
|
||||
if (step.Type == Step.StepType.Open)
|
||||
{
|
||||
if (OpenedValves.ContainsKey(step.Value.Item1)) throw new InvalidDataException();
|
||||
OpenedValves[step.Value.Item1] = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetPressureReleased()
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (int i =0; i< Steps.Count; i++)
|
||||
{
|
||||
var step = Steps[i];
|
||||
|
||||
if (step.Type == Step.StepType.Open)
|
||||
{
|
||||
int timeOpen = MaxSteps - (Int32.Parse(step.Value.Item2)+1);
|
||||
|
||||
total += Valves[step.Value.Item1].FlowRate * timeOpen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public int CompareTo(object? obj)
|
||||
{
|
||||
var other = obj as StepList;
|
||||
if (other == null) throw new ArgumentException();
|
||||
|
||||
return this.GetPressureReleased().CompareTo(other.GetPressureReleased());
|
||||
}
|
||||
|
||||
public static StepList GenerateBestPath(StepList sl)
|
||||
{
|
||||
if (!sl.CanContinue)
|
||||
return sl;
|
||||
|
||||
var lastStep = sl.Latest;
|
||||
|
||||
Valve valve = sl.Valves[lastStep.Value.Item1];
|
||||
|
||||
List<StepList> paths = new List<StepList>();
|
||||
paths.Add(sl);
|
||||
|
||||
// Just did a move, see if we need to open this valve
|
||||
if (lastStep.Type == StepList.Step.StepType.Move || lastStep.Type == Step.StepType.First)
|
||||
{
|
||||
// if it was a move, then our current valve is the target
|
||||
if (lastStep.Type == StepList.Step.StepType.Move)
|
||||
valve = sl.Valves[lastStep.Value.Item2];
|
||||
|
||||
// Valve isnt open and maybe should be
|
||||
if (!sl.isValveOpen(valve.Name) && valve.FlowRate > 0)
|
||||
{
|
||||
// Open valve path
|
||||
{
|
||||
StepList copy = new StepList(sl);
|
||||
|
||||
copy.AddStep(new Step(valve.Name, sl.StepCount));
|
||||
copy = GenerateBestPath(copy);
|
||||
|
||||
paths.Add(copy);
|
||||
}
|
||||
|
||||
// leave it closed path
|
||||
foreach (var tunnel in valve.AdjacentValves)
|
||||
{
|
||||
if (lastStep.Type == Step.StepType.Move && lastStep.Value.Item1 == tunnel.Name)
|
||||
continue; // Dont bounce back and forth, can go back if it was an open tho
|
||||
|
||||
StepList copy = new StepList(sl);
|
||||
|
||||
copy.AddStep(new Step(valve.Name, tunnel.Name));
|
||||
copy = GenerateBestPath(copy);
|
||||
|
||||
paths.Add(copy);
|
||||
|
||||
StepList toRet = paths[0];
|
||||
foreach (var item in paths)
|
||||
{
|
||||
if (item.GetPressureReleased() > toRet.GetPressureReleased())
|
||||
{
|
||||
toRet = item;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either the valve is already open or not worth opening
|
||||
foreach (var tunnel in valve.AdjacentValves)
|
||||
{
|
||||
if (lastStep.Type == Step.StepType.Move && lastStep.Value.Item1 == tunnel.Name)
|
||||
continue; // Dont bounce back and forth, can go back if it was an open tho
|
||||
|
||||
StepList copy = new StepList(sl);
|
||||
|
||||
copy.AddStep(new Step(valve.Name, tunnel.Name));
|
||||
copy = GenerateBestPath(copy);
|
||||
|
||||
paths.Add(copy);
|
||||
}
|
||||
|
||||
{
|
||||
StepList toRet = paths[0];
|
||||
foreach (var item in paths)
|
||||
{
|
||||
if (item.GetPressureReleased() > toRet.GetPressureReleased())
|
||||
{
|
||||
toRet = item;
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CaveGraph
|
||||
{
|
||||
public class CaveNode
|
||||
{
|
||||
public CaveNode(Valve v)
|
||||
{
|
||||
Valve = v;
|
||||
}
|
||||
|
||||
public List<CaveNode> AdjacentNodes { get; set; } = new List<CaveNode>();
|
||||
public List<int> AdjacentPathWeights { get; set; } = new List<int>();
|
||||
|
||||
public Valve Valve { get; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return Valve.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public int FlowRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return Valve.FlowRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CompressNodes(CaveNode cn, List<Valve> targets, int currentWeight)
|
||||
{
|
||||
foreach (var v in targets)
|
||||
{
|
||||
if (v.FlowRate > 0)
|
||||
{
|
||||
cn.AdjacentNodes.Add(CaveNodes[v.Name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, CaveNode> CaveNodes { get; }
|
||||
|
||||
public CaveGraph(Dictionary<string, Valve> valves)
|
||||
{
|
||||
CaveNodes = new Dictionary<string, CaveNode>();
|
||||
|
||||
foreach (var item in valves)
|
||||
{
|
||||
var valve = item.Value;
|
||||
// TODO
|
||||
CaveNode cn = new CaveNode(valve);
|
||||
//CaveNodes.Add(cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VolcanoData
|
||||
{
|
||||
public VolcanoData(string filename)
|
||||
{
|
||||
Valves = new Dictionary<string, Valve>();
|
||||
StartingValve = new Valve("AA", 0);
|
||||
|
||||
using (StreamReader reader = System.IO.File.OpenText(filename))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null) throw new InvalidDataException();
|
||||
|
||||
// Read in the valve name
|
||||
string newValveName = line.Split(' ')[1];
|
||||
int flowRate = Int32.Parse(line.Split('=')[1].Substring(0, line.Split("=")[1].IndexOf(';')));
|
||||
|
||||
if (!Valves.ContainsKey(newValveName))
|
||||
{
|
||||
Valves[newValveName] = new Valve(newValveName, flowRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
Valves[newValveName].FlowRate = flowRate;
|
||||
}
|
||||
|
||||
// Read in adjacent valves
|
||||
string[] valves;
|
||||
|
||||
if (line.Contains("to valve "))
|
||||
{
|
||||
valves = line.Split("to valve ")[1].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
}
|
||||
else if (line.Contains("to valves "))
|
||||
{
|
||||
valves = line.Split("valves ")[1].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
foreach (var adjacentValve in valves)
|
||||
{
|
||||
if (!Valves.ContainsKey(adjacentValve))
|
||||
{
|
||||
Valves[adjacentValve] = new Valve(adjacentValve, -1);
|
||||
}
|
||||
|
||||
Valves[newValveName].AdjacentValves.Add(Valves[adjacentValve]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StartingValve = Valves["AA"];
|
||||
|
||||
CaveGraph cg = new CaveGraph(Valves);
|
||||
}
|
||||
|
||||
public void Print()
|
||||
{
|
||||
foreach (var item in Valves)
|
||||
{
|
||||
Console.Write("{0}; tunnels lead to ", item.Value);
|
||||
|
||||
bool first = true;
|
||||
foreach (var v in item.Value.AdjacentValves)
|
||||
{
|
||||
if (!first) Console.Write(", ");
|
||||
Console.Write(v.Name);
|
||||
first = false;
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, Valve> Valves { get; }
|
||||
|
||||
public Valve StartingValve { get; }
|
||||
|
||||
public int GetMostPossiblePressureReleased(int maxSteps)
|
||||
{
|
||||
StepList sl = new StepList(Valves, maxSteps);
|
||||
|
||||
sl.AddStep(new StepList.Step());
|
||||
|
||||
sl = StepList.GenerateBestPath(sl);
|
||||
|
||||
return sl.GetPressureReleased();
|
||||
}
|
||||
}
|
||||
|
||||
class Valve
|
||||
{
|
||||
public Valve(string name, int flowRate)
|
||||
{
|
||||
Name = name;
|
||||
FlowRate = flowRate;
|
||||
AdjacentValves = new List<Valve>();
|
||||
}
|
||||
|
||||
public List<Valve> AdjacentValves
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public int FlowRate { get; set; }
|
||||
public string Name { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("Valve: ({0}) Flow ({1}): ", Name, FlowRate);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user