Initial Commit
This commit is contained in:
242
2022/Day21CSharp/Advent2022_Day21.cs
Normal file
242
2022/Day21CSharp/Advent2022_Day21.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using System.Numerics;
|
||||
|
||||
var exampleData = new ProblemData("example-input.txt");
|
||||
var puzzleData = new ProblemData("puzzle-input.txt");
|
||||
|
||||
Console.WriteLine("!! === Part01 === !!");
|
||||
Console.WriteLine("Example root yells: {0}", exampleData.GetMonkeyValuePart01("root"));
|
||||
Console.WriteLine("Puzzle root yells: {0}", puzzleData.GetMonkeyValuePart01("root"));
|
||||
|
||||
Console.WriteLine("!! === Part02 === !!");
|
||||
Console.WriteLine("Example human yells: {0}", exampleData.GetMonkeyValuePart02());
|
||||
Console.WriteLine("Puzzle human yells: {0}", puzzleData.GetMonkeyValuePart02());
|
||||
|
||||
abstract class MonkeyCommand
|
||||
{
|
||||
public MonkeyCommand(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public abstract BigInteger GetValue();
|
||||
|
||||
public string Name { get; protected set; }
|
||||
|
||||
public static bool DebugPrint { get; set; } = false;
|
||||
}
|
||||
|
||||
class MonkeyYellCommand
|
||||
: MonkeyCommand
|
||||
{
|
||||
public MonkeyYellCommand(string name, BigInteger val)
|
||||
: base(name)
|
||||
{
|
||||
Value = val;
|
||||
}
|
||||
|
||||
public BigInteger Value { get; set; }
|
||||
public override BigInteger GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
class MonkeyMathCommand
|
||||
: MonkeyCommand
|
||||
{
|
||||
public MonkeyMathCommand(string name, Dictionary<string, MonkeyCommand> lookupTable, string left, string right, char op)
|
||||
: base(name)
|
||||
{
|
||||
LookupTable = lookupTable;
|
||||
Left = left;
|
||||
Right = right;
|
||||
if ((op != '-') && (op != '+') && (op != '*') && (op != '/') && (op != '=')) throw new InvalidDataException();
|
||||
Op = op;
|
||||
}
|
||||
|
||||
public string Left { get; set; }
|
||||
public string Right { get; set; }
|
||||
|
||||
public BigInteger RightValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return LookupTable[Right].GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger LeftValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return LookupTable[Left].GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
public char Op { get; set; }
|
||||
|
||||
public char InverseOp
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Op)
|
||||
{
|
||||
case '+': return '-';
|
||||
case '-': return '+';
|
||||
case '*': return '/';
|
||||
case '/': return '*';
|
||||
default: throw new InvalidDataException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, MonkeyCommand> LookupTable { get; set; }
|
||||
|
||||
public override BigInteger GetValue()
|
||||
{
|
||||
BigInteger left = LeftValue;
|
||||
BigInteger right = RightValue;
|
||||
|
||||
switch (Op)
|
||||
{
|
||||
case '+':
|
||||
return left + right;
|
||||
case '-':
|
||||
return left - right;
|
||||
case '*':
|
||||
return left * right;
|
||||
case '/':
|
||||
return left / right;
|
||||
case '=':
|
||||
if (MonkeyCommand.DebugPrint && LookupTable["humn"].GetValue()%10000 == 0) Console.WriteLine("Comparing {0} v {1} with humn {2}", left, right, LookupTable["humn"].GetValue());
|
||||
return left - right;
|
||||
default: throw new InvalidDataException();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProblemData
|
||||
{
|
||||
private Dictionary<string, MonkeyCommand> CommandLookupPart01 { get; set; }
|
||||
private Dictionary<string, MonkeyCommand> CommandLookupPart02 { get; set; }
|
||||
|
||||
public ProblemData(string filename)
|
||||
{
|
||||
CommandLookupPart01 = new Dictionary<string, MonkeyCommand>();
|
||||
CommandLookupPart02 = new Dictionary<string, MonkeyCommand>();
|
||||
|
||||
using (StreamReader reader = System.IO.File.OpenText(filename))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null) throw new InvalidDataException();
|
||||
|
||||
var split = line.Split(':', StringSplitOptions.TrimEntries);
|
||||
var name = split[0];
|
||||
|
||||
MonkeyCommand monkey, monkey2;
|
||||
|
||||
// First see if its a value being yelled by the goddamned monkeys
|
||||
int val;
|
||||
if (int.TryParse(split[1], out val))
|
||||
{
|
||||
// It's a value monkey
|
||||
monkey = new MonkeyYellCommand(name, val);
|
||||
monkey2 = new MonkeyYellCommand(name, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a math monkey
|
||||
var mathline = split[1].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
monkey = new MonkeyMathCommand(name, CommandLookupPart01, mathline[0], mathline[2], mathline[1][0]);
|
||||
|
||||
char op = mathline[1][0];
|
||||
if (name == "root")
|
||||
op = '=';
|
||||
monkey2 = new MonkeyMathCommand(name, CommandLookupPart02, mathline[0], mathline[2], op);
|
||||
}
|
||||
|
||||
CommandLookupPart01[name] = monkey;
|
||||
CommandLookupPart02[name] = monkey2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger GetMonkeyValuePart01(string name)
|
||||
{
|
||||
return CommandLookupPart01[name].GetValue();
|
||||
}
|
||||
|
||||
public BigInteger GetMonkeyValuePart02()
|
||||
{
|
||||
MonkeyMathCommand rootCmd = (MonkeyMathCommand)CommandLookupPart02["root"];
|
||||
|
||||
// Find the side the human is on
|
||||
bool isHumanOnLeft = IsHumanOnLeft(CommandLookupPart02, rootCmd);
|
||||
BigInteger targetValue;
|
||||
|
||||
if (isHumanOnLeft)
|
||||
{
|
||||
targetValue = rootCmd.RightValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetValue = rootCmd.LeftValue;
|
||||
}
|
||||
|
||||
var humnCmd = (MonkeyYellCommand)CommandLookupPart02["humn"];
|
||||
BigInteger result = 0;
|
||||
BigInteger high = long.MaxValue, low = long.MinValue;
|
||||
BigInteger mid = low + (high - low) / 2;
|
||||
|
||||
bool incrementUp = false;
|
||||
humnCmd.Value = 1;
|
||||
var first = isHumanOnLeft ? rootCmd.LeftValue : rootCmd.RightValue;
|
||||
humnCmd.Value = 100;
|
||||
var second = isHumanOnLeft ? rootCmd.LeftValue : rootCmd.RightValue;
|
||||
|
||||
if (second > first) incrementUp = true;
|
||||
|
||||
while ((isHumanOnLeft ? rootCmd.LeftValue : rootCmd.RightValue) != targetValue)
|
||||
{
|
||||
humnCmd.Value = mid;
|
||||
|
||||
var newVal = isHumanOnLeft ? rootCmd.LeftValue : rootCmd.RightValue;
|
||||
|
||||
if ((incrementUp && (newVal > targetValue)) || (!incrementUp && (newVal < targetValue)))
|
||||
{
|
||||
high = low + (high - low) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = low + (high - low) / 2;
|
||||
}
|
||||
|
||||
mid = low + (high - low) / 2;
|
||||
}
|
||||
|
||||
return CommandLookupPart02["humn"].GetValue();
|
||||
}
|
||||
|
||||
private static bool IsHumanOnLeft(Dictionary<string,MonkeyCommand> dict, MonkeyMathCommand command)
|
||||
{
|
||||
MonkeyYellCommand humnCmd = (MonkeyYellCommand)dict["humn"];
|
||||
|
||||
var ogRight = command.RightValue;
|
||||
var ogLeft = command.LeftValue;
|
||||
|
||||
humnCmd.Value += 10;
|
||||
|
||||
var newRight = command.RightValue;
|
||||
var newLeft = command.LeftValue;
|
||||
|
||||
humnCmd.Value -= 10;
|
||||
|
||||
if (ogLeft == newLeft) return false;
|
||||
else if (ogRight == newRight) return true;
|
||||
else throw new InvalidDataException();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user