242 lines
7.2 KiB
C#
242 lines
7.2 KiB
C#
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();
|
|
}
|
|
|
|
} |