Ejemplo n.º 1
0
        private void ToggleCodelChooser()
        {
            switch (CC)
            {
            case CodelChooser.Left:
                CC = CodelChooser.Right;
                return;

            case CodelChooser.Right:
                CC = CodelChooser.Left;
                return;
            }
            if (IsDebug)
            {
                CcChanged?.Invoke(this, CC);
            }
        }
Ejemplo n.º 2
0
        public void Interpret(Codel[,] image, Stream stdout, Stream stdin)
        {
            if (State != ExecutionState.Idle)
            {
                throw new InvalidOperationException("Can't start two interpretations at once!");
            }
            State = ExecutionState.Running;
            using (StreamWriter stdoutWriter = new StreamWriter(stdout, Encoding))
            {
                stdoutWriter.AutoFlush = true;
                using (StreamReader stdinReader = new StreamReader(stdin, Encoding))
                {
                    DP = DirectionPointer.Right;
                    if (IsDebug)
                    {
                        DpChanged?.Invoke(this, DP);
                    }
                    CC = CodelChooser.Left;
                    if (IsDebug)
                    {
                        CcChanged?.Invoke(this, CC);
                    }
                    Stack.Clear();
                    List <ColorBlock> colorBlocks = new List <ColorBlock>();
                    for (int x = 0; x < image.GetLength(0); x++)
                    {
                        for (int y = 0; y < image.GetLength(1); y++)
                        {
                            if (image[x, y].Position.x != x || image[x, y].Position.y != y)
                            {
                                throw new ArgumentException("Position noted in Codel class not equal to position noted in grid!");
                            }

                            bool nextTo(Codel c, int xPos, int yPos)
                            {
                                return((Math.Abs(c.Position.x - xPos) == 1 && c.Position.y == yPos) || (Math.Abs(c.Position.y - yPos) == 1 && c.Position.x == xPos));
                            }

                            bool hasAdjacentCodel(ColorBlock b)
                            {
                                return(b.Codels.Any(c => nextTo(c, x, y) && c.Color == image[x, y].Color));
                            }

                            if (!colorBlocks.Any(hasAdjacentCodel))
                            {
                                var colorBlock = new ColorBlock(image[x, y]);
                                colorBlocks.Add(colorBlock);
                            }
                            else
                            {
                                if (colorBlocks.Count(hasAdjacentCodel) > 1)
                                {
                                    var block = new ColorBlock(image[x, y]);
                                    colorBlocks.ForEach(b => { if (hasAdjacentCodel(b))
                                                               {
                                                                   b.Codels.ForEach(c => block.Codels.Add(c));
                                                               }
                                                        });
                                    colorBlocks.RemoveAll(hasAdjacentCodel);
                                    colorBlocks.Add(block);
                                }
                                else
                                {
                                    colorBlocks.Find(hasAdjacentCodel).Codels.Add(image[x, y]);
                                }
                            }
                        }
                    }

                    Codel currentCodel;
                    (int x, int y)currentPosition = (0, 0);
                    ColorBlock            currentColorBlock, previousColorBlock;
                    Codel                 nextCodel;
                    List <(int x, int y)> whiteTrace = new List <(int x, int y)>();
                    if (IsDebug)
                    {
                        EnterColorBlock?.Invoke(this, colorBlocks.Find(x => x.Codels.Contains(image[0, 0])));
                    }
                    while (true)
                    {
                        currentCodel = image[currentPosition.x, currentPosition.y];
                        nextCodel    = null;
                        if (currentCodel.Color == CodelColor.White)
                        {
                            whiteTrace.Add(currentPosition);
                            for (int i = 0; i < 4; i++)
                            {
                                int xFactor = 0, yFactor = 0;
                                switch (DP)
                                {
                                case DirectionPointer.Right:
                                    xFactor = 1;
                                    break;

                                case DirectionPointer.Down:
                                    yFactor = 1;
                                    break;

                                case DirectionPointer.Left:
                                    xFactor = -1;
                                    break;

                                case DirectionPointer.Up:
                                    yFactor = -1;
                                    break;
                                }
                                int xPos = currentPosition.x + xFactor;
                                int yPos = currentPosition.y + yFactor;
                                if (xPos < 0 || xPos >= image.GetLength(0) || yPos < 0 || yPos >= image.GetLength(1) || image[xPos, yPos].Color == CodelColor.Black)
                                {
                                    ToggleCodelChooser();
                                    TurnDirectionPointer();
                                    continue;
                                }
                                currentPosition = (xPos, yPos);
                                break;
                            }
                            if (whiteTrace.Any(x => x.x == currentPosition.x && x.y == currentPosition.y))
                            {
                                State = ExecutionState.Idle;
                                return;
                            }
                            continue;
                        }
                        whiteTrace.Clear();
                        if (IsDebug)
                        {
                            Thread.Sleep(StepDelay);
                        }
                        while (IsDebug && State == ExecutionState.Paused)
                        {
                        }
                        if (State == ExecutionState.OneMoreStep)
                        {
                            State = ExecutionState.Paused;
                        }
                        else if (State == ExecutionState.Idle)
                        {
                            return;
                        }
                        currentColorBlock = colorBlocks.Find(x => x.Codels.Contains(currentCodel));

                        Codel furthestCodel = null;
                        for (int i = 0; i < 8; i++)
                        {
                            int xFactor = 0, yFactor = 0;
                            switch (DP)
                            {
                            case DirectionPointer.Right:
                                xFactor = 1;
                                break;

                            case DirectionPointer.Down:
                                yFactor = 1;
                                break;

                            case DirectionPointer.Left:
                                xFactor = -1;
                                break;

                            case DirectionPointer.Up:
                                yFactor = -1;
                                break;
                            }

                            furthestCodel = currentColorBlock.FindFurthestCodel(DP, CC);
                            int xPos = furthestCodel.Position.x + xFactor;
                            int yPos = furthestCodel.Position.y + yFactor;
                            if (xPos < 0 || xPos >= image.GetLength(0) || yPos < 0 || yPos >= image.GetLength(1) || image[xPos, yPos].Color == CodelColor.Black)
                            {
                                if (i % 2 == 0)
                                {
                                    ToggleCodelChooser();
                                }
                                else
                                {
                                    TurnDirectionPointer();
                                }
                                continue;
                            }
                            nextCodel       = image[xPos, yPos];
                            currentPosition = (xPos, yPos);
                            break;
                        }

                        if (nextCodel == null)
                        {
                            State = ExecutionState.Idle;
                            return;
                        }
                        previousColorBlock = currentColorBlock;
                        currentColorBlock  = colorBlocks.Find(x => x.Codels.Contains(nextCodel));
                        if (IsDebug && nextCodel.Color != CodelColor.White)
                        {
                            EnterColorBlock?.Invoke(this, currentColorBlock);
                        }
                        var operation = CodelColor.CalculateOperation(furthestCodel.Color, nextCodel.Color);
                        if (IsDebug)
                        {
                            OperationSelected?.Invoke(this, operation);
                        }

                        // check if operation is impossible and needs to be skipped
                        bool skip;
                        switch (operation)
                        {
                        case Operation.add:
                        case Operation.greater:
                        case Operation.subtract:
                        case Operation.multiply:
                        case Operation.roll:
                            skip = Stack.Count < 2;
                            break;

                        case Operation.divide:
                        case Operation.mod:
                            skip = Stack.Count < 2 || Stack.Peek() == 0;
                            break;

                        case Operation.duplicate:
                        case Operation.pointer:
                        case Operation.out_number:
                        case Operation.pop:
                        case Operation.not:
                        case Operation.@switch:
                        case Operation.out_char:
                            skip = Stack.Count < 1;
                            break;

                        default:
                            skip = false;
                            break;
                        }

                        // execute operation
                        if (!skip)
                        {
                            int top, sectop, b;
                            switch (operation)
                            {
                            case Operation.nop:
                                break;

                            case Operation.add:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                Stack.Push(sectop + top);
                                break;

                            case Operation.divide:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                Stack.Push(sectop / top);
                                break;

                            case Operation.greater:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                if (sectop > top)
                                {
                                    Stack.Push(1);
                                }
                                else
                                {
                                    Stack.Push(0);
                                }
                                break;

                            case Operation.duplicate:
                                Stack.Push(Stack.Peek());
                                break;

                            case Operation.in_char:
                                b = stdinReader.Read();
                                if (b != -1)
                                {
                                    Stack.Push(b);
                                }
                                else
                                {
                                    OperationFailed?.Invoke(this, operation);
                                }
                                break;

                            case Operation.push:
                                Stack.Push(previousColorBlock.Size);
                                break;

                            case Operation.subtract:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                Stack.Push(sectop - top);
                                break;

                            case Operation.mod:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                if (top > 0)
                                {
                                    Stack.Push(sectop % top);
                                }
                                else
                                {
                                    Stack.Push((sectop % Math.Abs(top)) - Math.Abs(top));
                                }
                                break;

                            case Operation.pointer:
                                TurnDirectionPointer(Stack.Pop());
                                break;

                            case Operation.roll:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                if (sectop < 0 || sectop > Stack.Count)
                                {
                                    Stack.Push(sectop);
                                    Stack.Push(top);
                                    if (IsDebug)
                                    {
                                        OperationFailed?.Invoke(this, operation);
                                    }
                                    break;
                                }
                                Roll(sectop, top);
                                break;

                            case Operation.out_number:
                                OutputNumber(stdoutWriter, Stack.Pop());
                                break;

                            case Operation.pop:
                                Stack.Pop();
                                break;

                            case Operation.multiply:
                                top    = Stack.Pop();
                                sectop = Stack.Pop();
                                Stack.Push(sectop * top);
                                break;

                            case Operation.not:
                                top = Stack.Pop();
                                if (top == 0)
                                {
                                    Stack.Push(1);
                                }
                                else
                                {
                                    Stack.Push(0);
                                }
                                break;

                            case Operation.@switch:
                                ToggleCodelChooser(Stack.Pop());
                                break;

                            case Operation.in_number:
                                ReadNumber(stdinReader);
                                break;

                            case Operation.out_char:
                                stdoutWriter.Write((char)Stack.Pop());
                                break;
                            }
                        }
                        else if (IsDebug)
                        {
                            OperationFailed?.Invoke(this, operation);
                        }
                    }
                }
            }
        }