Files
2020/Q08.cs
2020-12-08 08:40:55 -06:00

151 lines
4.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace _2020
{
class Q08
{
static List<Tuple<string, int>> instructions = new List<Tuple<string, int>>();
public static void Go()
{
MakeList();
Part1();
Part2();
}
static void MakeList()
{
foreach (var line in File.ReadAllLines("08input.txt"))
{
var parts = line.Split(' ');
if (parts.Count() != 2)
{
throw new Exception("malformed input");
}
instructions.Add(new Tuple<string, int>(parts[0], Convert.ToInt32(parts[1])));
}
}
static void ProcessInstruction(List<Tuple<string, int>> inst, ref int i, ref int accum)
{
switch (inst[i].Item1)
{
case "acc":
accum += inst[i].Item2;
i++;
break;
case "jmp":
i += inst[i].Item2;
break;
case "nop":
i++;
break;
}
}
static Tuple<int, bool> RunProgram(List<Tuple<string, int>> program)
{
var accum = 0;
var executed = new Dictionary<int, int>();
for (var i = 0; ;)
{
if (program.Count <= i)
{
return new Tuple<int, bool>(accum, true);
}
if (executed.ContainsKey(i))
{
break;
}
executed.Add(i, 1);
ProcessInstruction(program, ref i, ref accum);
}
return new Tuple<int, bool>(accum, false);
}
static void Part1()
{
var result = RunProgram(instructions);
if (result.Item2)
{
throw new Exception("Exited normally - shouldn't have");
}
Debug.WriteLine($"Q08Part1: accum value={result.Item1}");
}
static void Part2()
{
// should probably have used RunProgram here, but ended up replacing the first-encountered instruction instead of
// moving through the program and changing the first unchanged instruction i came across. this seemed possibly
// more efficient? i don't know.
bool bExited = false;
var instructionToChange = "jmp";
var instructionToReplace = "nop";
var replacedInstructions = new List<int>();
var accum = 0;
while (!bExited)
{
accum = 0;
var copy = new List<Tuple<string, int>>(instructions);
var executed = new Dictionary<int, int>();
bool bChanged = false;
for (var i = 0; ;)
{
if (copy.Count <= i)
{
bExited = true;
break;
}
if (executed.ContainsKey(i))
{
if (!bChanged)
{
// this whole section is hacky
if (instructionToChange != "jmp")
{
throw new Exception("nothing worked");
}
Debug.WriteLine($"changing {instructionToChange} to {instructionToReplace} didn't work - flipping");
var tmp = instructionToChange;
instructionToChange = instructionToReplace;
instructionToReplace = tmp;
replacedInstructions = new List<int>();
}
break;
}
executed.Add(i, 1);
if (copy[i].Item1 == instructionToChange && !bChanged && !replacedInstructions.Contains(i))
{
replacedInstructions.Add(i);
bChanged = true;
copy[i] = new Tuple<string, int>(instructionToReplace, copy[i].Item2);
}
ProcessInstruction(copy, ref i, ref accum);
}
}
Debug.WriteLine($"Q08Part2: accum value={accum}");
}
}
}