163 lines
6.8 KiB
C#
163 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
|
|
namespace AoC {
|
|
|
|
internal class Day8 {
|
|
|
|
private enum Instruction {
|
|
ACC, JMP, NOP
|
|
}
|
|
|
|
private record Command(Instruction ins, int value);
|
|
|
|
private ImmutableDictionary<string, Instruction> InstructionFromString =
|
|
new Dictionary<string, Instruction> {
|
|
{ "acc", Instruction.ACC },
|
|
{ "jmp", Instruction.JMP },
|
|
{ "nop", Instruction.NOP }
|
|
}.ToImmutableDictionary();
|
|
|
|
private Regex rx = new(@"^(?<ins>\w+) (?<value>(\+|\-)\d+)");
|
|
|
|
private bool DoesItLoop(List<Command> commands, int index, ref int accumulator) {
|
|
ISet<int> commandIndices = new HashSet<int>();
|
|
while (index >= 0 && index < commands.Count && !commandIndices.Contains(index)) {
|
|
commandIndices.Add(index);
|
|
|
|
var command = commands[index];
|
|
(accumulator, index) = command.ins switch {
|
|
Instruction.ACC => (accumulator + command.value, index + 1),
|
|
Instruction.JMP => (accumulator, index + command.value),
|
|
Instruction.NOP => (accumulator, index + 1),
|
|
_ => throw new ArgumentException("Du doofer Hund!")
|
|
};
|
|
}
|
|
|
|
return commandIndices.Contains(index);
|
|
}
|
|
|
|
internal void Solve() {
|
|
var readLines = File.ReadAllText("day8/input").Split("\n", StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
Command LineToCommandSelector(string line) {
|
|
var groups = rx.Match(line).Groups;
|
|
return new Command(InstructionFromString[groups["ins"].Value], int.Parse(groups["value"].Value));
|
|
}
|
|
|
|
var commands = readLines.Select(LineToCommandSelector).ToList();
|
|
|
|
SortedSet<int> commandIndices = new SortedSet<int>();
|
|
int index = 0;
|
|
int accumulator = 0;
|
|
while (!commandIndices.Contains(index)) {
|
|
commandIndices.Add(index);
|
|
|
|
var command = commands[index];
|
|
(accumulator, index) = command.ins switch {
|
|
Instruction.ACC => (accumulator + command.value, index + 1),
|
|
Instruction.JMP => (accumulator, index + command.value),
|
|
Instruction.NOP => (accumulator, index + 1),
|
|
_ => throw new ArgumentException("Du doofer Hund!")
|
|
};
|
|
}
|
|
|
|
Console.WriteLine(accumulator);
|
|
|
|
foreach (var commandIndex in commandIndices.Reverse()) {
|
|
index = 0;
|
|
accumulator = 0;
|
|
if (commands[commandIndex].ins == Instruction.ACC) {
|
|
continue;
|
|
}
|
|
if (commands[commandIndex].ins == Instruction.JMP) {
|
|
commands[commandIndex] = new Command(Instruction.NOP, commands[commandIndex].value);
|
|
if (!DoesItLoop(commands, index, ref accumulator)) {
|
|
break;
|
|
}
|
|
commands[commandIndex] = new Command(Instruction.JMP, commands[commandIndex].value);
|
|
} else {
|
|
commands[commandIndex] = new Command(Instruction.JMP, commands[commandIndex].value);
|
|
if (!DoesItLoop(commands, index, ref accumulator)) {
|
|
break;
|
|
}
|
|
commands[commandIndex] = new Command(Instruction.NOP, commands[commandIndex].value);
|
|
}
|
|
}
|
|
|
|
Console.WriteLine(accumulator);
|
|
}
|
|
|
|
private record Info(int index, int accumulator);
|
|
|
|
private static void ExecuteInstruction(List<Command> commands, ref int index, ref int accumulator) {
|
|
var command = commands[index];
|
|
(accumulator, index) = command.ins switch {
|
|
Instruction.ACC => (accumulator + command.value, index + 1),
|
|
Instruction.JMP => (accumulator, index + command.value),
|
|
Instruction.NOP => (accumulator, index + 1),
|
|
_ => throw new ArgumentException("Du doofer Hund!")
|
|
};
|
|
}
|
|
|
|
private bool DoesItLoop(List<Command> commands, int index, ref int accumulator, ISet<int> visitedInstructions) {
|
|
while (index >= 0 && index < commands.Count && !visitedInstructions.Contains(index)) {
|
|
visitedInstructions.Add(index);
|
|
ExecuteInstruction(commands, ref index, ref accumulator);
|
|
}
|
|
return visitedInstructions.Contains(index);
|
|
}
|
|
|
|
internal void SolveOn() {
|
|
|
|
var readLines = File.ReadAllText("day8/input").Split("\n", StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
Command LineToCommandSelector(string line) {
|
|
var groups = rx.Match(line).Groups;
|
|
return new Command(InstructionFromString[groups["ins"].Value], int.Parse(groups["value"].Value));
|
|
}
|
|
|
|
var commands = readLines.Select(LineToCommandSelector).ToList();
|
|
|
|
ISet<int> commandIndices = new HashSet<int>();
|
|
Stack<Info> commandInfo = new Stack<Info>();
|
|
int index = 0;
|
|
int accumulator = 0;
|
|
while (!commandIndices.Contains(index)) {
|
|
commandIndices.Add(index);
|
|
commandInfo.Push(new Info(index, accumulator));
|
|
|
|
ExecuteInstruction(commands, ref index, ref accumulator);
|
|
}
|
|
|
|
Console.WriteLine(accumulator);
|
|
|
|
Instruction switchInstruction(Instruction ins) => ins == Instruction.NOP ? Instruction.JMP : Instruction.NOP;
|
|
|
|
int tempAccumulator = -1;
|
|
while (commandInfo.Count > 0) {
|
|
var current = commandInfo.Pop();
|
|
if (commands[current.index].ins == Instruction.ACC) {
|
|
continue;
|
|
}
|
|
|
|
commands[current.index] = new Command(switchInstruction(commands[current.index].ins), commands[current.index].value);
|
|
tempAccumulator = current.accumulator;
|
|
commandIndices.Remove(current.index);
|
|
if (!DoesItLoop(commands, current.index, ref tempAccumulator, commandIndices)) {
|
|
break;
|
|
}
|
|
commands[current.index] = new Command(switchInstruction(commands[current.index].ins), commands[current.index].value);
|
|
}
|
|
|
|
Console.WriteLine(tempAccumulator);
|
|
}
|
|
|
|
|
|
}
|
|
} |