Last active
June 4, 2023 03:39
-
-
Save GuyInGrey/e9bd05cc0b1e338eecba49cb7e01d397 to your computer and use it in GitHub Desktop.
SynacorSharp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using SynacorSharp.Runtime; | |
| namespace SynacorSharp.ConsoleApp | |
| { | |
| internal class Program | |
| { | |
| static void Main() | |
| { | |
| var engine = new SynacorEngine() | |
| { | |
| Data = SynacorEngineData.FromBinary("Challenge/challenge.bin") | |
| }; | |
| while (!engine.Data.IsHalted) | |
| { | |
| engine.Step(); | |
| if (engine.Data.OutputQueue.TryDequeue(out var output)) | |
| { | |
| Console.Write(output); | |
| } | |
| if (engine.Data.InputRequested) | |
| { | |
| var input = Console.ReadLine() + "\n"; | |
| foreach (var c in input) | |
| { | |
| engine.Data.InputQueue.Enqueue(c); | |
| } | |
| } | |
| } | |
| Console.ForegroundColor = ConsoleColor.Red; | |
| Console.WriteLine($"Execution halted by script; Steps completed: {engine.Data.TotalStepsCompleted}; Pointer: {engine.Data.Pointer}"); | |
| Console.ForegroundColor = ConsoleColor.White; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Runtime.CompilerServices; | |
| namespace SynacorSharp.Runtime | |
| { | |
| public class SynacorEngine | |
| { | |
| public SynacorEngineData Data { get; set; } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] | |
| private ushort GetValue(ushort address) | |
| { | |
| if (address >= SynacorEngineData.Modulo + 8) { address = (ushort)(address % SynacorEngineData.Modulo); } | |
| return address < SynacorEngineData.Modulo ? address : Data.Registers[address - SynacorEngineData.Modulo]; | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] | |
| private ushort LoadOpParameter(int parameterIndex, bool isNumeric) | |
| { | |
| var v = Data.Memory[Data.Pointer + 1 + parameterIndex]; | |
| if (isNumeric) { v = GetValue(v); } | |
| return v; | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] | |
| private void SetValue(ushort address, ushort value) | |
| { | |
| if (address >= SynacorEngineData.Modulo + 8) { address = (ushort)(address % SynacorEngineData.Modulo); } | |
| if (address < SynacorEngineData.Modulo) | |
| { | |
| Data.Memory[address] = value; | |
| } | |
| else | |
| { | |
| Data.Registers[address - SynacorEngineData.Modulo] = value; | |
| } | |
| } | |
| public void Step() | |
| { | |
| var opCode = (SynacorOpCode)Data.Memory[Data.Pointer]; | |
| ushort parameterCount = 0; | |
| var staticPointer = false; | |
| switch (opCode) | |
| { | |
| case SynacorOpCode.Halt: | |
| Data.IsHalted = true; | |
| staticPointer = true; | |
| break; | |
| case SynacorOpCode.Set: | |
| parameterCount = 2; | |
| SetValue(LoadOpParameter(0, false), LoadOpParameter(1, true)); | |
| break; | |
| case SynacorOpCode.Push: | |
| parameterCount = 1; | |
| Data.Stack.Push(LoadOpParameter(0, true)); | |
| break; | |
| case SynacorOpCode.Pop: | |
| parameterCount = 1; | |
| SetValue(LoadOpParameter(0, false), Data.Stack.Pop()); | |
| break; | |
| case SynacorOpCode.IsEqualTo: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), LoadOpParameter(1, true) == LoadOpParameter(2, true) ? (ushort)1 : (ushort)0); | |
| break; | |
| case SynacorOpCode.IsGreaterThan: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), LoadOpParameter(1, true) > LoadOpParameter(2, true) ? (ushort)1 : (ushort)0); | |
| break; | |
| case SynacorOpCode.Jump: | |
| parameterCount = 1; | |
| staticPointer = true; | |
| Data.Pointer = LoadOpParameter(0, true); | |
| break; | |
| case SynacorOpCode.JumpIfNonZero: | |
| parameterCount = 2; | |
| if (LoadOpParameter(0, true) != 0) | |
| { | |
| staticPointer = true; | |
| Data.Pointer = LoadOpParameter(1, true); | |
| } | |
| break; | |
| case SynacorOpCode.JumpIfZero: | |
| parameterCount = 2; | |
| if (LoadOpParameter(0, true) == 0) | |
| { | |
| staticPointer = true; | |
| Data.Pointer = LoadOpParameter(1, true); | |
| } | |
| break; | |
| case SynacorOpCode.Add: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), (ushort)((LoadOpParameter(1, true) + LoadOpParameter(2, true)) % SynacorEngineData.Modulo)); | |
| break; | |
| case SynacorOpCode.Multiply: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), (ushort)((LoadOpParameter(1, true) * LoadOpParameter(2, true)) % SynacorEngineData.Modulo)); | |
| break; | |
| case SynacorOpCode.Mod: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), (ushort)(LoadOpParameter(1, true) % LoadOpParameter(2, true))); | |
| break; | |
| case SynacorOpCode.BitwiseAnd: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), (ushort)(LoadOpParameter(1, true) & LoadOpParameter(2, true))); | |
| break; | |
| case SynacorOpCode.BitwiseOr: | |
| parameterCount = 3; | |
| SetValue(LoadOpParameter(0, false), (ushort)(LoadOpParameter(1, true) | LoadOpParameter(2, true))); | |
| break; | |
| case SynacorOpCode.BitwiseNot: | |
| parameterCount = 2; | |
| var not = ~LoadOpParameter(1, true); | |
| if (LoadOpParameter(1, true) < SynacorEngineData.Modulo) { not -= SynacorEngineData.Modulo; } | |
| SetValue(LoadOpParameter(0, false), (ushort)not); | |
| break; | |
| case SynacorOpCode.ReadMemory: | |
| parameterCount = 2; | |
| SetValue(LoadOpParameter(0, false), Data.Memory[LoadOpParameter(1, true)]); | |
| break; | |
| case SynacorOpCode.WriteMemory: | |
| parameterCount = 2; | |
| SetValue(LoadOpParameter(0, true), LoadOpParameter(1, true)); | |
| break; | |
| case SynacorOpCode.Call: | |
| parameterCount = 1; | |
| staticPointer = true; | |
| Data.Stack.Push((ushort)(Data.Pointer + 2)); | |
| Data.Pointer = LoadOpParameter(0, true); | |
| break; | |
| case SynacorOpCode.Return: | |
| staticPointer = true; | |
| Data.Pointer = Data.Stack.Pop(); | |
| break; | |
| case SynacorOpCode.Output: | |
| parameterCount = 1; | |
| Data.OutputQueue.Enqueue((char)LoadOpParameter(0, true)); | |
| break; | |
| case SynacorOpCode.Input: | |
| char input; | |
| while (!Data.InputQueue.TryDequeue(out input)) { Thread.Sleep(1); } | |
| SetValue(LoadOpParameter(0, false), (ushort)input); | |
| break; | |
| case SynacorOpCode.NoOperator: break; | |
| } | |
| if (!staticPointer) { Data.Pointer += (ushort)(parameterCount + 1); } | |
| var newOpCode = (SynacorOpCode)Data.Memory[Data.Pointer]; | |
| if (newOpCode == SynacorOpCode.Input && Data.InputQueue.IsEmpty) | |
| { | |
| Data.InputRequested = true; | |
| } | |
| else | |
| { | |
| Data.InputRequested = false; | |
| } | |
| Data.TotalStepsCompleted++; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Concurrent; | |
| namespace SynacorSharp.Runtime | |
| { | |
| [Serializable] | |
| public class SynacorEngineData | |
| { | |
| public const ushort Modulo = 32768; | |
| public ushort[] Memory { get; set; } = new ushort[32768 /* 15-bit range */]; | |
| public ushort[] Registers { get; set; } = new ushort[8]; | |
| public Stack<ushort> Stack { get; set; } = new(); | |
| public ushort Pointer { get; set; } = 0; | |
| public bool IsHalted { get; set; } = false; | |
| public int TotalStepsCompleted { get; set; } = 0; | |
| public ConcurrentQueue<char> InputQueue { get; set; } = new(); | |
| public ConcurrentQueue<char> OutputQueue { get; set; } = new(); | |
| public bool InputRequested { get; set; } = false; | |
| public static SynacorEngineData FromBinary(string filePath) | |
| { | |
| var data = new SynacorEngineData(); | |
| var bytes = File.ReadAllBytes(filePath); | |
| for (var i = 0; i < bytes.Length; i += 2) | |
| { | |
| data.Memory[i / 2] = (ushort)(bytes[i] + (bytes[i + 1] * 256)); | |
| } | |
| return data; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace SynacorSharp.Runtime | |
| { | |
| public enum SynacorOpCode : ushort | |
| { | |
| Halt = 0, | |
| Set = 1, | |
| Push = 2, | |
| Pop = 3, | |
| IsEqualTo = 4, | |
| IsGreaterThan = 5, | |
| Jump = 6, | |
| JumpIfNonZero = 7, | |
| JumpIfZero = 8, | |
| Add = 9, | |
| Multiply = 10, | |
| Mod = 11, | |
| BitwiseAnd = 12, | |
| BitwiseOr = 13, | |
| BitwiseNot = 14, | |
| ReadMemory = 15, | |
| WriteMemory = 16, | |
| Call = 17, | |
| Return = 18, | |
| Output = 19, | |
| Input = 20, | |
| NoOperator = 21, | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment