public async Task ArrayToTableString(byte[] output, int outputLenth = 0) { if (output.Length == 0) { throw new ArgumentException("File is empty"); } if (OutputActionAsync.GetInvocationList() == null || OutputActionAsync.GetInvocationList().Length == 0) { isProgressAsync = false; } else { isProgressAsync = true; } var writingLenth = outputLenth != 0 ? outputLenth : output.Length; for (int i = 0; i < writingLenth; i++) { if (i % byteLineWidth == 0 && i != 0) { if (isProgressAsync) { await OutputActionAsync?.Invoke("|\n"); await OutputActionAsync?.Invoke($"{RowLine}\n"); } else { OutputAction?.Invoke("|\n"); OutputAction?.Invoke($"{RowLine}\n"); } } if (isProgressAsync) { await OutputActionAsync?.Invoke(AlignCentre(output[i])); } else { OutputAction?.Invoke(AlignCentre(output[i])); } WritingProgess = (double)(i + 1) / writingLenth; } Finalize?.Invoke(); }
/// <summary> /// Sets the raw output. /// Used internally. /// </summary> /// <param name="rawOutput">The raw output.</param> void ICanParseOutput.SetRawOutput(IEnumerable <string>?rawOutput) { string[] outputlines = Array.Empty <string>(); T? parsed = default; if (rawOutput != null) { outputlines = rawOutput.ToArray(); parsed = OutputParser.Parse(outputlines); } RawOutputAction?.Invoke(outputlines); if (parsed != null) { OutputAction?.Invoke(parsed); } }
public async Task ArrayToTableString(bool[] output, int outputLenth = 0) { if (output.Length == 0) { throw new ArgumentException("File is empty"); } var writingLenth = outputLenth != 0 ? outputLenth : output.Length; for (int i = 0; i < writingLenth; i++) { if (i % binaryLineWidth == 0 && i != 0) { if (isProgressAsync) { await OutputActionAsync?.Invoke("|\n"); await OutputActionAsync?.Invoke($"{RowLine}\n"); } else { OutputAction?.Invoke("|\n"); OutputAction?.Invoke($"{RowLine}\n"); } } if (isProgressAsync) { await OutputActionAsync?.Invoke($"| {Convert.ToInt16(output[i])} "); } else { OutputAction?.Invoke($"| {Convert.ToInt16(output[i])} "); } WritingProgess = (double)(i + 1) / writingLenth; } Finalize?.Invoke(); }
public void Execute() { Random random = new Random(); int maxX = Grid.GetLength(1); int maxY = Grid.GetLength(0); int x = 0; int y = 0; Directions direction = 0; bool stringMode = false; bool skip = false; while (true) { // cyclic boundaries if (x < 0 || y < 0 || x >= maxX || y >= maxY) { switch (direction) { case Directions.Right: x = 0; break; case Directions.Down: y = 0; break; case Directions.Left: x = maxX - 1; break; case Directions.Up: y = maxY - 1; break; } } // char instruction = Grid[y, x]; Debug.WriteLine($"Instruction at {x},{y} = {instruction} string:{stringMode} skip:{skip}"); // skip or not if (skip) { skip = false; // skip instruction Debug.WriteLine("BRIDGE OFF: skipping current instruction."); } // string mode or not else if (stringMode) { // push instruction as string if (instruction == '"') { Debug.WriteLine("STRING MODE OFF"); stringMode = false; } else { int operand = instruction; Debug.WriteLine($"STRING MODE: PUSH {operand}"); Push(operand); } } else { switch (instruction) { //Push this number on the stack case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': int digit = instruction - 48; Push(digit); Debug.WriteLine($"PUSH DIGIT {digit}"); break; //Addition: Pop a and b, then push a+b case '+': //Subtraction: Pop a and b, then push b-a case '-': //Multiplication: Pop a and b, then push a*b case '*': //Integer division: Pop a and b, then push b/a, rounded towards 0. case '/': //Modulo: Pop a and b, then push the remainder of the integer division of b/a. case '%': PerformMathOperation(instruction); break; //Logical NOT: Pop a value. If the value is zero, push 1; otherwise, push zero. case '!': { int operand = Pop(); int result = operand == 0 ? 1 : 0; Debug.WriteLine($"NOT({operand})={result}"); Push(result); } break; //Greater than: Pop a and b, then push 1 if b>a, otherwise zero. case '`': { int operand2 = Pop(); int operand1 = Pop(); int result = operand1 > operand2 ? 1 : 0; Debug.WriteLine($"GREATER({operand1},{operand2})={result}"); Push(result); } break; //Start moving right case '>': direction = Directions.Right; Debug.WriteLine("MOVE RIGHT"); break; //Start moving left case '<': direction = Directions.Left; Debug.WriteLine("MOVE LEFT"); break; //Start moving up case '^': direction = Directions.Up; Debug.WriteLine("MOVE UP"); break; //Start moving down case 'v': direction = Directions.Down; Debug.WriteLine("MOVE DOWN"); break; //Start moving in a random cardinal direction case '?': direction = (Directions)random.Next(4); Debug.WriteLine($"MOVE RANDOM={direction}"); break; //Pop a value; move right if value=0, left otherwise case '_': { int operand = Pop(); direction = operand == 0 ? Directions.Right : Directions.Left; Debug.WriteLine($"CHANGE HORIZONTAL({operand})={direction}"); } break; //Pop a value; move down if value=0, up otherwise case '|': { int operand = Pop(); direction = operand == 0 ? Directions.Down : Directions.Up; Debug.WriteLine($"CHANGE VERTICAL({operand})={direction}"); } break; //Start string mode: push each character's ASCII value all the way up to the next " case '\"': stringMode = true; Debug.WriteLine("STRING MODE ON"); break; //Duplicate value on top of the stack case ':': { int operand = Pop(); Push(operand); Push(operand); Debug.WriteLine($"DUP({operand})"); } break; //Swap two values on top of the stack case '\\': { int operand2 = Pop(); int operand1 = Pop(); Push(operand2); Push(operand1); Debug.WriteLine($"SWAP({operand1},{operand2})"); } break; //Pop value from the stack and discard it case '$': { Pop(); // pop and discard Debug.WriteLine("POP"); } break; //Pop value and output as an integer followed by a space case '.': { int operand = Pop(); Debug.WriteLine($"OUT NUMBER({operand})"); OutputAction?.Invoke(operand.ToString()); } break; //Pop value and output as ASCII character case ',': { int outputAsInt = Pop(); char operand = (char)(outputAsInt % 255); OutputAction?.Invoke(operand.ToString()); Debug.WriteLine($"OUT CHAR({operand})"); } break; //Bridge: Skip next cell case '#': skip = true; Debug.WriteLine("BRIDGE ON: skipping next instruction"); break; //A "put" call (a way to store a value for later use). Pop y, x, and v, then change the character at (x,y) in the program to the character with ASCII value v case 'p': { int putY = Pop(); int putX = Pop(); int putValue = Pop(); Grid[putY, putX] = (char)putValue; Debug.WriteLine($"PUT({putX},{putY})={putValue}"); } break; //A "get" call (a way to retrieve data in storage). Pop y and x, then push ASCII value of the character at that position in the program case 'g': { int getY = Pop(); int getX = Pop(); int getValue = Grid[getY, getX]; Push(getValue); Debug.WriteLine($"GET({getX},{getY})={getValue}"); } break; //Ask user for a number and push it case '&': { string inputAsString = InputFunc?.Invoke(); if (string.IsNullOrWhiteSpace(inputAsString)) { Debug.WriteLine("IN NUMBER failed: null or empty input"); } else { int operand; if (!int.TryParse(inputAsString, out operand)) { Debug.WriteLine($"IN NUMBER failed: invalid input {inputAsString}"); } else { Push(operand); Debug.WriteLine($"IN NUMBER({operand})"); } } } break; //Ask user for a character and push its ASCII value case '~': { string inputAsString = InputFunc?.Invoke(); if (string.IsNullOrEmpty(inputAsString)) { Debug.WriteLine("IN CHAR failed: null or empty input"); } else { int inputChar = inputAsString[0] % 255; Debug.WriteLine($"IN CHAR({inputChar})"); Push(inputChar); } } break; //End program case '@': Debug.WriteLine("END OF PROGRAM"); return; //NOP case ' ': Debug.WriteLine("NOP"); break; //Unknown instruction default: Debug.WriteLine($"Unknown instruction:{instruction}"); break; } } // Move instruction pointers according to direction MoveDirectionUntilInstructionFound(direction, stringMode, ref x, ref y); } }
/* * Lightness * Hue 0 1 2 * 0 / push pop * 1 add sub mul * 2 div mod not * 3 greater pointer switch * 4 dup roll in number * 5 in char out number out char */ private void PerformInstruction(int fromColorIndex, int toColorIndex, int codelCount) { int hueDiff = HueDiff(fromColorIndex, toColorIndex); int lightnessDiff = LightnessDiff(fromColorIndex, toColorIndex); Debug.WriteLine($"PerformInstruction: From{ColorIndexToString(fromColorIndex)} to {ColorIndexToString(toColorIndex)} => Hue:{hueDiff} Lightness:{lightnessDiff}"); switch (hueDiff) { case 0: // NOP, Push, Pop switch (lightnessDiff) { case 0: // NOP Debug.WriteLine("Action: NOP"); break; case 1: // Push Debug.WriteLine($"Action: PUSH {codelCount}"); Stack.Push(codelCount); break; case 2: // Pop if (Stack.Count == 0) { Debug.WriteLine("Action: POP failed: stack underflow"); } else { Debug.WriteLine("Action: POP"); Stack.Pop(); // Pop and discard } break; } break; case 1: // Add, Sub, Mul switch (lightnessDiff) { case 0: // Add // Pop 2 values, add them and push back result PerformMathOperation('+'); break; case 1: // Sub // Pop 2 values, sub (top from second top) them and push back result PerformMathOperation('-'); break; case 2: // Mul // Pop 2 values, multiply them and push back result PerformMathOperation('*'); break; } break; case 2: // Div, Mod, Not switch (lightnessDiff) { case 0: // Div // Pop 2 values, divide (second top by top) them and push back result PerformMathOperation('/'); break; case 1: // Mod // Pop 2 values, mod (second top modulo top) them and push back result PerformMathOperation('%'); break; case 2: // Not // Pop 1 value, not (0->1, 0 otherwise) it and push back result if (Stack.Count == 0) { Debug.WriteLine("Action: NOT failed: stack underflow"); } else { int operand = Stack.Pop(); int result = operand == 0 ? 1 : 0; Debug.WriteLine($"Action: NOT({operand})={result}"); Stack.Push(result); } break; } break; case 3: // greater, pointer, switch switch (lightnessDiff) { case 0: // Greater // Pop 2 values, if second top > top push 1, push 0 otherwise if (Stack.Count < 2) { Debug.WriteLine("Action: GREATER failed: stack underflow"); } else { int operand2 = Stack.Pop(); int operand1 = Stack.Pop(); int result = operand1 > operand2 ? 1 : 0; Debug.WriteLine($"Action: GREATER({operand1},{operand2})={result}"); Stack.Push(result); } break; case 1: // Pointer // Pop 1 value, turn DP clockwise if positive, counterclockwise otherwise if (Stack.Count == 0) { Debug.WriteLine("Action: POINTER failed: stack underflow"); } else { int operand = Stack.Pop(); int absOperand = operand; Func <PointerDirections, PointerDirections> func; if (absOperand > 0) { func = TurnDirectionPointerClockwise; } else { absOperand = -absOperand; func = TurnDirectionPointerCounterClockwise; } for (int i = 0; i < absOperand % 4; i++) { DirectionPointer = func(DirectionPointer); } Debug.WriteLine($"Action: POINTER({operand})={DirectionPointer}"); } break; case 2: // Switch // Pop 1 value, toggle CC that many times if (Stack.Count == 0) { Debug.WriteLine("Action: SWITCH failed: stack underflow"); } else { int operand = Stack.Pop(); for (int i = 0; i < operand % 4; i++) { CodelChooser = ToggleCodelChooser(CodelChooser); } Debug.WriteLine($"Action: SWITCH({operand})={CodelChooser}"); } break; } break; case 4: // dup, roll, in number switch (lightnessDiff) { case 0: // Duplicate // Push a copy of top value if (Stack.Count == 0) { Debug.WriteLine("Action: DUPLICATE failed: stack underflow"); } else { int operand = Stack.Peek(); Stack.Push(operand); Debug.WriteLine($"Action: DUPLICATE({operand})"); } break; case 1: // Roll // Pop 2 values, roll remaining stack entries to a depth equals to the second top by a number of rolls equal to top (see http://www.dangermouse.net/esoteric/piet.html) // roll of depth k: move top at position k in stack and move up every value above k'th position if (Stack.Count < 2) { Debug.WriteLine("Action: ROLL failed: stack underflow"); } else { int roll = Stack.Pop(); int depth = Stack.Pop(); if (depth < 0) { Debug.WriteLine($"Action: ROLL failed: negative depth {depth}"); } else if (Stack.Count < depth) { Debug.WriteLine($"Action: ROLL failed: stack underflow {depth}"); } else { Stack.Roll(roll, depth); } } break; case 2: // In number // Read a number from stdin and push it string inputAsString = InputFunc?.Invoke(); int inputNumber; if (!int.TryParse(inputAsString, out inputNumber)) { Debug.WriteLine($"Action: IN NUMBER failed: invalid input {inputAsString}"); } else { Debug.WriteLine($"Action: IN NUMBER({inputNumber})"); Stack.Push(inputNumber); } break; } break; case 5: // in char, out number, out char switch (lightnessDiff) { case 0: // In char // Read a char from stdin and push it string inputAsString = InputFunc?.Invoke(); if (string.IsNullOrEmpty(inputAsString)) { Debug.WriteLine("Action: IN CHAR failed: null or empty input"); } else { int inputChar = inputAsString[0] % 255; Debug.WriteLine($"Action: IN CHAR({inputChar})"); Stack.Push(inputChar); } break; case 1: // Out number // Pop 1 value, print it on stdout as number if (Stack.Count == 0) { Debug.WriteLine("Action: OUT NUMBER failed: stack underflow"); } else { int operand = Stack.Pop(); Debug.WriteLine($"Action: OUT NUMBER({operand})"); OutputAction?.Invoke(operand.ToString()); } break; case 2: // Out char // Pop 1 value, print it on stdout as char if (Stack.Count == 0) { Debug.WriteLine("Action: OUT CHAR failed: stack underflow"); } else { int outputAsInt = Stack.Pop(); char operand = (char)(outputAsInt % 255); Debug.WriteLine($"Action: OUT CHAR({operand})"); OutputAction?.Invoke(operand.ToString()); } break; } break; } }
public void Execute() { Debug.WriteLine("Execution start"); // init registers int a = 0; // accumulator int c = 0; // code pointer int d = 0; // data pointer while (true) { int instruction = Memory[c]; if (instruction > 32 && instruction < 127) // [33-126] { int opCodeEncrypted = (c + instruction - 33) % 94; char opCode = DecryptionTable[opCodeEncrypted]; Debug.WriteLine($"Opcode:{opCodeEncrypted} => {opCode}"); // Perform instruction switch (opCode) { case 'j': // 40: mov d,[d] Debug.WriteLine("Instruction: MOV"); d = Memory[d]; break; case 'i': // 4: jmp[d] Debug.WriteLine("Instruction: JMP"); c = Memory[d]; break; case '*': // 39: rotr [d] | mov a,d Debug.WriteLine("Instruction: ROTR"); Memory[d] = Memory[d] / 3 + Memory[d] % 3 * 19683; a = Memory[d]; break; case 'p': // 62: crazy [d],a | mov a,[d] Debug.WriteLine("Instruction: CRAZY"); Memory[d] = Crazy(a, Memory[d]); a = Memory[d]; break; case '<': // 5: stdout Debug.WriteLine("Instruction: STDOUT"); OutputAction?.Invoke((char)(a & 0xFF)); break; case '/': // 23: stdin Debug.WriteLine("Instruction: STDIN"); char?input = InputFunc?.Invoke(); if (input == null) { Debug.WriteLine("Null input"); } else { if (input.Value == '\n') { a = 10; } //else if (input == EOF) // TODO // a = int.MaxValue; else { a = input.Value; } } break; case 'v': // 81: end Debug.WriteLine("Instruction: END OF PROGRAM"); return; case 'o': // 68: nop Debug.WriteLine("Instruction: NOP"); break; default: Debug.WriteLine("Instruction: INVALID"); break; } // Encrypt instruction Memory[c] = EncryptionTable[Memory[c] - 33]; // Advance c and d if (c == MaxValue) { c = 0; } else { c++; } if (d == MaxValue) { d = 0; } else { d++; } } else { Debug.WriteLine($"Skipping invalid instruction {instruction}"); } } }