示例#1
0
        public void ThrowOutOfPlateauExceptionWhenMoveToNewCoordinatesExceedsBorders()
        {
            DirectionClass direction = DirectionFactory.GetDirection('S');

            var result = Record.Exception(() => borderStrategy.MoveToNewCoordinates(coordinates, direction));

            Assert.NotNull(result);
            Assert.IsType <OutOfPlateauException>(result);
        }
        public void MoveToCoordinatesWhenMoveToNewCoordinatesStaysInBorders()
        {
            DirectionClass direction = DirectionFactory.GetDirection('N');

            var result = borderStrategy.MoveToNewCoordinates(coordinates, direction);

            int expectedCoordX = 0;
            int expectedCoordY = 1;

            Assert.NotNull(result);
            Assert.Equal(expectedCoordX, result.coordX);
            Assert.Equal(expectedCoordY, result.coordY);
        }
        public void WaitAtTheBorderWhenMoveToNewCoordinatesExceedsBorders()
        {
            DirectionClass direction = DirectionFactory.GetDirection('S');

            var result = borderStrategy.MoveToNewCoordinates(coordinates, direction);

            int expectedCoordX = 0;
            int expectedCoordY = 0;

            Assert.NotNull(result);
            Assert.Equal(expectedCoordX, result.coordX);
            Assert.Equal(expectedCoordY, result.coordY);
        }
        /// <summary>
        /// Throws OutOfPlateauException if the Rover tries to move out of the plateau borders, else returns new Coordinates to move
        /// </summary>
        /// <param name="currentCoordinates">Rover's current coordinates</param>
        /// <param name="currentDirection">Rover's current direction</param>
        /// <returns>New Coordinates to move according to given direction</returns>
        public override Coordinates MoveToNewCoordinates(Coordinates currentCoordinates, DirectionClass currentDirection)
        {
            Coordinates newCoordinates = currentCoordinates + currentDirection.GetMoveForwardCoordinates();

            if (newCoordinates.coordX < lowerBoundryBorderCoordinates.coordX || newCoordinates.coordY < lowerBoundryBorderCoordinates.coordY || newCoordinates.coordX > upperBoundryBorderCoordinates.coordX || newCoordinates.coordY > upperBoundryBorderCoordinates.coordY)
            {
                throw new OutOfPlateauException();
            }

            return(newCoordinates);
        }
示例#5
0
 public abstract Coordinates MoveToNewCoordinates(Coordinates currentCoordinates, DirectionClass currentDirection);
示例#6
0
 /// <summary>
 /// Turns the Rover 90 degrees to right
 /// </summary>
 public void TurnRight()
 {
     currentDirection = currentDirection.GetRightDirection();
 }
示例#7
0
 /// <summary>
 /// Turns the Rover 90 degrees to left
 /// </summary>
 public void TurnLeft()
 {
     currentDirection = currentDirection.GetLeftDirection();
 }
示例#8
0
        static private int ResolveNeutralAndWeak(
            IList<DirectionClass>   characterClass,        // [IN / OUT]
            int                     classIndex,            // [IN]
            int                     runLength,             // [IN]
            DirectionClass          sor,                   // [IN]
            DirectionClass          eor,                   // [IN]
            byte                    runLevel,              // [IN]
            State                   stateIn,               // [IN], [OPTIONAL]
            State                   stateOut,              // [OUT],[OPTIONAL]
            bool                    previousStrongIsArabic,// [IN], OPTIONAL
            Flags                   flags                  // [IN]
        )
        {
            int                      startOfNeutrals    = PositionInvalid;
            int                      startOfDelayed     = PositionInvalid;
            DirectionClass           lastClass          = DirectionClass.ClassInvalid;
            DirectionClass           lastStrongClass    = DirectionClass.ClassInvalid;
            DirectionClass           lastNumericClass   = DirectionClass.ClassInvalid;
            DirectionClass           startingClass      = DirectionClass.ClassInvalid;
            DirectionClass           currentClass       = DirectionClass.ClassInvalid;
            StateMachineState        state;
            bool                     previousClassIsArabic = false;
            bool                     ArabicNumberAfterLeft = false;
            int                      lengthResolved = 0;

            if (runLength == 0)
            {
                return 0;
            }

            if (stateIn != null)
            {
                lastStrongClass = stateIn.LastStrongClass;

                if (stateIn.LastNumberClass != DirectionClass.ClassInvalid)
                {
                    lastNumericClass = startingClass =
                                       lastClass =
                                       stateIn.LastNumberClass;
                }
                else
                {
                    startingClass = lastClass = lastStrongClass;
                }

            }
            else if (previousStrongIsArabic)
            {
                startingClass = DirectionClass.ArabicLetter;
                lastClass = lastStrongClass = sor;
                previousClassIsArabic = true;
            }
            else
            {
                startingClass = lastClass = lastStrongClass = sor;
            }

            state = ClassToState[(int) startingClass];

            // We have two types of classes that needs delayed resolution:
            // Neutrals and other classes such as CS, ES, ET, BN, NSM that needs look ahead.
            // We keep a separate pointer for the start of neutrals and another pointer
            // for the those other classes (if needed since its resolution might be delayed).
            // Also, we need the last strong class for neutral resolution and the last
            // general class (that is not BN or MSM) for NSM resolution.

            // The simple idea of all actions is that we always resolve neutrals starting
            // from 'startOfNeutrals' and when we are sure about delayed weak type
            // resolution, we resolve it starting from 'startOfDelayed' else we point by
            // 'startOfNeutrals' as resolve it as neutral.
            int counter = 0;
            for (counter = 0; counter < runLength; counter++)
            {
                currentClass = characterClass[counter + classIndex];

                // We index action and next state table by class.
                // If we got a calss that should have been resolved already or a bogus
                // value, return what we were able to resolve so far.

                if (CharProperty[5, (int) currentClass]==0)
                {
                    return lengthResolved;
                }
                StateMachineAction action = Action[(int) state, (int)currentClass];

                // Need to record last numeric type so that when
                // we continue from a previous call, we can correctly resolve something
                // like L AN at the end of the first call and EN at the start of the
                // next call.

                if (CharProperty[4, (int) currentClass]==1)
                {
                    lastNumericClass = currentClass;
                }

                // If we have previousClassIsArabic flag set, we need its efect to
                // last only till the first strong character in the run.

                if(CharProperty[0, (int) currentClass]==1)
                {
                    previousClassIsArabic = false;
                }

                switch (action)
                {
                case StateMachineAction.ST_ST:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                              "Cannot have unresolved neutrals. State: " +
                              state.ToString() +
                              ", Class: " + currentClass.ToString());

                    if (currentClass == DirectionClass.ArabicLetter)
                    {
                        characterClass[counter + classIndex] = DirectionClass.Right;
                    }

                    if (startOfDelayed != PositionInvalid)
                    {
                        startOfNeutrals = startOfDelayed;

                        ResolveNeutrals(characterClass,
                                        classIndex + startOfNeutrals,
                                        counter    - startOfNeutrals,
                                        ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                        characterClass[counter + classIndex],
                                        runLevel);

                        startOfNeutrals = startOfDelayed = PositionInvalid;
                    }

                    if ((currentClass != DirectionClass.ArabicNumber)  ||
                        ((currentClass == DirectionClass.ArabicNumber) &&
                         (lastStrongClass == DirectionClass.Right)))
                    {
                        lastStrongClass = currentClass;
                    }

                    if ((currentClass == DirectionClass.ArabicNumber) &&
                        (lastStrongClass == DirectionClass.Left))
                    {
                        ArabicNumberAfterLeft = true;
                    }
                    else
                    {
                        ArabicNumberAfterLeft = false;
                    }

                    lastClass = currentClass;
                    break;

                case StateMachineAction.ST_ET:
                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() +
                             ", Class: "+ currentClass.ToString());

                    if (startOfNeutrals == PositionInvalid)
                    {
                       startOfNeutrals =  startOfDelayed;
                    }

                    if (currentClass == DirectionClass.ArabicLetter)
                    {
                        characterClass[counter + classIndex] = DirectionClass.Right;
                    }

                    ResolveNeutrals(characterClass,
                                    classIndex + startOfNeutrals,
                                    counter    - startOfNeutrals,
                                    ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                    characterClass[counter + classIndex],
                                    runLevel);

                    startOfNeutrals = startOfDelayed = PositionInvalid;

                    if ((currentClass != DirectionClass.ArabicNumber) ||
                        ((currentClass == DirectionClass.ArabicNumber) &&
                         (lastStrongClass == DirectionClass.Right)))
                    {
                        lastStrongClass = currentClass;
                    }

                    if ((currentClass == DirectionClass.ArabicNumber) &&
                        (lastStrongClass == DirectionClass.Left))
                    {
                        ArabicNumberAfterLeft = true;
                    }
                    else
                    {
                        ArabicNumberAfterLeft = false;
                    }
                    lastClass = currentClass;
                    break;

                case StateMachineAction.ST_NUMSEP:
                    {
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() +
                             ", Class: "+ currentClass.ToString());

                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() +
                             " Class: "+ currentClass.ToString());
                    bool processed = false;

                    if (currentClass == DirectionClass.ArabicLetter)
                    {
                        // Rule W3, change all AL to R. 
                        characterClass[counter + classIndex] = DirectionClass.Right;
                    }

                    if (((lastStrongClass == DirectionClass.ArabicLetter) || previousClassIsArabic) &&
                        ((currentClass == DirectionClass.EuropeanNumber && (flags & Flags.OverrideEuropeanNumberResolution) == 0) ||
                         (currentClass == DirectionClass.ArabicNumber)))
                    {
                        // Rule W2: Change EN to AN if it follows AL.
                        characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                        bool commonSeparator = true;
                        int  commonSeparatorCount = 0;

                        for (int i = startOfDelayed; i < counter; i++)
                        {
                            if (characterClass[i + classIndex] != DirectionClass.CommonSeparator &&
                                characterClass[i + classIndex] != DirectionClass.BoundaryNeutral)
                            {
                                commonSeparator = false;
                                break;
                            }

                            if (characterClass[i + classIndex] == DirectionClass.CommonSeparator )
                            {
                                commonSeparatorCount++;
                            }

                        }

                        if (commonSeparator && (commonSeparatorCount == 1))
                        {
                            // Rule W4: In sequence of AN CS AN, change CS to AN.
                            ChangeType(characterClass,
                                       classIndex + startOfDelayed,
                                       counter    -  startOfDelayed,
                                       characterClass[counter + classIndex]);

                            processed = true;
                        }
                    }
                    else if ((lastStrongClass == DirectionClass.Left) &&
                             (currentClass    == DirectionClass.EuropeanNumber))
                    {
                        // Rule W7: Change EN to L if it follows L.
                        characterClass[counter + classIndex] = DirectionClass.Left;
                    }

                    if (!processed)
                    {
                        startOfNeutrals =  startOfDelayed;

                        ResolveNeutrals(characterClass,
                                        classIndex + startOfNeutrals,
                                        counter    - startOfNeutrals,
                                        ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                        characterClass[counter + classIndex],
                                        runLevel);
                    }

                    startOfNeutrals = startOfDelayed = PositionInvalid;

                    if ((currentClass != DirectionClass.ArabicNumber)  ||
                        ((currentClass == DirectionClass.ArabicNumber) &&
                         (lastStrongClass == DirectionClass.Right)))
                    {
                        if (!(((lastStrongClass == DirectionClass.Left) ||
                                (lastStrongClass == DirectionClass.ArabicLetter)) &&
                                (currentClass == DirectionClass.EuropeanNumber)))
                        {
                            lastStrongClass = currentClass;
                        }
                    }

                    if ((currentClass == DirectionClass.ArabicNumber) &&
                        (lastStrongClass == DirectionClass.Left))
                    {
                        ArabicNumberAfterLeft = true;
                    }
                    else
                    {
                        ArabicNumberAfterLeft = false;
                    }

                    lastClass = currentClass;

                    if (characterClass[counter + classIndex] == DirectionClass.ArabicNumber)
                    {
                        currentClass = DirectionClass.ArabicNumber;
                    }
                    }
                    break;

                case StateMachineAction.ST_N:
                    Debug.Assert(startOfNeutrals != PositionInvalid,
                             "Must have unresolved neutrals. State: " +
                             state.ToString() +", Class: "+
                             currentClass.ToString());

                    if (currentClass == DirectionClass.ArabicLetter)
                    {
                        characterClass[counter + classIndex] = DirectionClass.Right;
                    }

                    ResolveNeutrals(characterClass,
                                    classIndex + startOfNeutrals,
                                    counter    - startOfNeutrals,
                                    ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                    characterClass[counter + classIndex],
                                    runLevel);

                    startOfNeutrals = startOfDelayed = PositionInvalid;

                    if ((currentClass != DirectionClass.ArabicNumber) ||
                        ((currentClass == DirectionClass.ArabicNumber) &&
                         (lastStrongClass == DirectionClass.Right)))
                    {
                        lastStrongClass = currentClass;
                    }

                    if ((currentClass == DirectionClass.ArabicNumber) &&
                        (lastStrongClass == DirectionClass.Left))
                    {
                        ArabicNumberAfterLeft = true;
                    }
                    else
                    {
                        ArabicNumberAfterLeft = false;
                    }
                    lastClass = currentClass;
                    break;

                case StateMachineAction.EN_N:
                    Debug.Assert(startOfNeutrals != PositionInvalid,
                             "Must have unresolved neutrals. State: " +
                             state.ToString() + ", Class: "+
                             currentClass.ToString());

                    if ((flags & Flags.OverrideEuropeanNumberResolution) == 0 &&
                            ((lastStrongClass == DirectionClass.ArabicLetter) ||
                             previousClassIsArabic)
                        )
                    {
                        // Rule W2: EN changes to AN if it follows AL.
                        characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                        currentClass            = DirectionClass.ArabicNumber;
                    }
                    else if (lastStrongClass == DirectionClass.Left)
                    {
                        // Rule W7: EN changes to L if it follows L.
                        characterClass[counter + classIndex] = DirectionClass.Left;
                    }

                    ResolveNeutrals(characterClass,
                                    classIndex + startOfNeutrals,
                                    counter    - startOfNeutrals,
                                    ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                    characterClass[counter + classIndex],
                                    runLevel);

                    startOfNeutrals = startOfDelayed = PositionInvalid;
                    ArabicNumberAfterLeft = false;
                    lastClass = currentClass;
                    break;

                case StateMachineAction.SEP_ST:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if (startOfDelayed != PositionInvalid)
                    {
                        startOfNeutrals = startOfDelayed;
                        startOfDelayed = PositionInvalid;
                    }
                    else
                    {
                        startOfNeutrals = counter;
                    }
                    lastClass = currentClass;
                    break;

                case StateMachineAction.CS_NUM:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if (startOfDelayed == PositionInvalid)
                    {
                        startOfDelayed = counter;
                    }
                    lastClass = currentClass;
                    break;

                case StateMachineAction.SEP_ET:
                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if (startOfNeutrals == PositionInvalid)
                    {
                        startOfNeutrals = startOfDelayed;
                    }
                    startOfDelayed = PositionInvalid;
                    lastClass = DirectionClass.GenericNeutral;
                    break;

                case StateMachineAction.SEP_NUMSEP:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    startOfNeutrals = startOfDelayed;
                    startOfDelayed = PositionInvalid;
                    lastClass = DirectionClass.GenericNeutral;
                    break;

                case StateMachineAction.SEP_N:
                    Debug.Assert(startOfNeutrals != PositionInvalid,
                             "Must have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    startOfDelayed = PositionInvalid;
                    break;

                case StateMachineAction.ES_AN:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if (startOfDelayed != PositionInvalid)
                    {
                        startOfNeutrals = startOfDelayed;
                        startOfDelayed = PositionInvalid;
                    }
                    else
                    {
                        startOfNeutrals = counter;
                    }
                    lastClass = DirectionClass.GenericNeutral;
                    break;

                case StateMachineAction.ET_ET:
                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());
                    Debug.Assert(lastClass == DirectionClass.EuropeanTerminator,
                             "Last class must be ET. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());
                    break;

                case StateMachineAction.ET_NUMSEP:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    startOfNeutrals = startOfDelayed;
                    startOfDelayed = counter;
                    lastClass = currentClass;
                    break;

                case StateMachineAction.ET_EN:
                    if (startOfDelayed == PositionInvalid)
                    {
                        startOfDelayed = counter;
                    }

                    if (!((lastStrongClass == DirectionClass.ArabicLetter) || previousClassIsArabic))
                    {
                        if (lastStrongClass == DirectionClass.Left)
                        {
                            characterClass[counter + classIndex] = DirectionClass.Left;
                        }
                        else
                        {
                            characterClass[counter + classIndex] = DirectionClass.EuropeanNumber;
                        }

                        ChangeType(characterClass,
                                   classIndex + startOfDelayed,
                                   counter    -  startOfDelayed,
                                   characterClass[counter + classIndex]);

                    startOfDelayed = PositionInvalid;
                    }
                    lastClass = DirectionClass.EuropeanNumber;

                    // According to the rules W4, W5, and W6 If we have a sequence EN ET ES EN
                    // we should treat ES as ON

                    if ( counter<runLength-1        &&
                        (characterClass[counter + 1 + classIndex] == DirectionClass.EuropeanSeparator||
                         characterClass[counter + 1 + classIndex] == DirectionClass.CommonSeparator))
                    {
                        characterClass[counter + 1 + classIndex]  = DirectionClass.GenericNeutral;
                    }

                    break;

                case StateMachineAction.ET_N:
                    Debug.Assert(startOfNeutrals != PositionInvalid,
                             "Must have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if (startOfDelayed == PositionInvalid)
                    {
                        startOfDelayed = counter;
                    }

                    lastClass = currentClass;
                    break;

                case StateMachineAction.NUM_NUMSEP:
                    Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    Debug.Assert(startOfDelayed != PositionInvalid,
                             "Must have delayed weak classes. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                    if ((lastStrongClass == DirectionClass.ArabicLetter) ||
                        previousClassIsArabic || ArabicNumberAfterLeft)
                    {   
                        if ((flags & Flags.OverrideEuropeanNumberResolution) == 0)
                        {
                            characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                        }
                    }
                    else if (lastStrongClass == DirectionClass.Left)
                    {
                        characterClass[counter + classIndex] = DirectionClass.Left;
                    }
                    else
                    {
                        lastStrongClass = currentClass;
                    }

                    ChangeType(characterClass,
                                classIndex + startOfDelayed,
                                counter    -  startOfDelayed,
                                characterClass[counter + classIndex]);

                    startOfDelayed = PositionInvalid;
                    lastClass = currentClass;
                    break;

               case StateMachineAction.EN_L:
                   Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                   if (lastStrongClass == DirectionClass.Left)
                   {
                       characterClass[counter + classIndex] = DirectionClass.Left;
                   }

                   if (startOfDelayed != PositionInvalid)
                   {
                       startOfNeutrals = startOfDelayed;

                       ResolveNeutrals(characterClass,
                                       classIndex + startOfNeutrals,
                                       counter    - startOfNeutrals,
                                       ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                       characterClass[counter + classIndex],
                                       runLevel);

                       startOfNeutrals = startOfDelayed = PositionInvalid;
                   }
                   lastClass = currentClass;
                   break;

               case StateMachineAction.NUM_NUM:
                   Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                   if ((flags & Flags.OverrideEuropeanNumberResolution) == 0 &&
                       (lastStrongClass == DirectionClass.ArabicLetter || previousClassIsArabic)
                      ) 
                   {
                       // W2: EN changes to AN if it follows AL.
                       characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                       currentClass                         = DirectionClass.ArabicNumber;
                   }
                   else if (lastStrongClass == DirectionClass.Left)
                   {
                       characterClass[counter + classIndex] = DirectionClass.Left;
                   }

                   if (startOfDelayed != PositionInvalid)
                   {
                       startOfNeutrals = startOfDelayed;

                       ResolveNeutrals(characterClass,
                                       classIndex + startOfNeutrals,
                                       counter    - startOfNeutrals,
                                       ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                       characterClass[counter + classIndex],
                                       runLevel);

                       startOfNeutrals = startOfDelayed = PositionInvalid;
                   }

                   if ( (currentClass == DirectionClass.ArabicNumber) &&
                        (lastStrongClass == DirectionClass.Left))
                   {
                       ArabicNumberAfterLeft = true;
                   }
                   else
                   {
                       ArabicNumberAfterLeft = false;
                   }
                   lastClass = currentClass;
                   break;

               case StateMachineAction.EN_AL:
                   Debug.Assert(startOfNeutrals == PositionInvalid,
                             "Cannot have unresolved neutrals. State: " +
                             state.ToString() + ", Class: " +
                             currentClass.ToString());

                   if ((flags & Flags.OverrideEuropeanNumberResolution) == 0)
                   {
                       // W2: EN changes to AN if it follows AL.
                       // We will go onto Arabic number state (S_AN). 
                       characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                   }
                   else
                   {
                       // Change the current state such that we will go onto European number state (S_EN) 
                       // instead of Arabic number state (S_AN). As rule W2 is ignored, "EN following AL" 
                       // is the same as "EN following L".
                       state = StateMachineState.S_L;
                   }

                   if (startOfDelayed != PositionInvalid)
                   {
                       startOfNeutrals = startOfDelayed;

                       ResolveNeutrals(characterClass,
                                       classIndex + startOfNeutrals,
                                       counter    - startOfNeutrals,
                                       ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                       characterClass[counter + classIndex],
                                       runLevel);

                       startOfNeutrals = startOfDelayed = PositionInvalid;
                   }
                   lastClass = characterClass[counter + classIndex];
                   break;

               case StateMachineAction.EN_ET:
                   Debug.Assert(startOfDelayed != PositionInvalid,
                            "Must have delayed weak classes. State: " +
                            state.ToString() + ", Class: " +
                            currentClass.ToString());

                   if ((lastStrongClass == DirectionClass.ArabicLetter) ||
                        previousClassIsArabic)
                   {
                       if ((flags & Flags.OverrideEuropeanNumberResolution) == 0)
                       {
                           // W2: EN changes to AN if it follows AL
                           characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                           currentClass = DirectionClass.ArabicNumber;
                       }

                       if (startOfNeutrals == PositionInvalid)
                       {
                           ResolveNeutrals(characterClass,
                                           classIndex + startOfDelayed,
                                           counter    - startOfDelayed,
                                           ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                           characterClass[counter + classIndex],
                                           runLevel);
                       }
                       else
                       {
                           ResolveNeutrals(characterClass,
                                           classIndex + startOfNeutrals,
                                           counter    - startOfNeutrals,
                                           ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                           characterClass[counter + classIndex],
                                           runLevel);
                       }
                   }
                   else if (lastStrongClass == DirectionClass.Left)
                   {
                       characterClass[counter + classIndex] = DirectionClass.Left;

                       ChangeType(characterClass,
                                  classIndex + startOfDelayed,
                                  counter -  startOfDelayed,
                                  characterClass[counter + classIndex]);

                       if (startOfNeutrals != PositionInvalid)
                       {
                           ResolveNeutrals(characterClass,
                                           classIndex + startOfNeutrals,
                                           startOfDelayed -  startOfNeutrals,
                                           ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                           characterClass[counter + classIndex],
                                           runLevel);
                       }
                       ArabicNumberAfterLeft = false;
                   }
                   else
                   {
                       ChangeType(characterClass,
                                  classIndex + startOfDelayed,
                                  counter -  startOfDelayed,
                                  DirectionClass.EuropeanNumber);

                       if (startOfNeutrals != PositionInvalid)
                       {
                           ResolveNeutrals(characterClass,
                                           classIndex + startOfNeutrals,
                                           startOfDelayed -  startOfNeutrals,
                                           ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                           currentClass,
                                           runLevel);
                       }
                   }
                   startOfNeutrals = startOfDelayed = PositionInvalid;
                   lastClass = currentClass;
                   break;

               case StateMachineAction.BN_ST:
                   if (startOfDelayed == PositionInvalid)
                   {
                       startOfDelayed = counter;
                   }
                   break;

               case StateMachineAction.NSM_ST:
                    // Here is an NSM (non-space-mark) followed by a Strong.
                    // We can always resolve the NSM to its final class
                    if ((lastStrongClass == DirectionClass.ArabicLetter))
                    {
                        if (lastClass == DirectionClass.EuropeanNumber)
                        {
                            if ((flags & Flags.OverrideEuropeanNumberResolution) == 0)
                            {
                                // Applying rule W1 & W2
                                // W1: NSM changes to the class of previous char
                                // W2: EN following AL changes to AN
                                characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                            }
                            else
                            {
                                // Just apply rule W1.
                                characterClass[counter + classIndex] = DirectionClass.EuropeanNumber;
                            }
                        }
                        else if (lastClass != DirectionClass.ArabicNumber)
                        {
                            // Rule W3: AL is considered as R.
                            characterClass[counter + classIndex] = DirectionClass.Right;
                        }
                        else
                        {
                            // last char is an AN.
                            characterClass[counter + classIndex] = DirectionClass.ArabicNumber;
                        }
                    }
                    else
                    {
                        characterClass[counter + classIndex] = ArabicNumberAfterLeft
                                                    || lastClass == DirectionClass.ArabicNumber ?
                                                    DirectionClass.ArabicNumber :
                                                        lastClass==DirectionClass.EuropeanNumber &&
                                                        lastStrongClass != DirectionClass.Left
                                                        ? DirectionClass.EuropeanNumber  : lastStrongClass;
                    }

                    if (startOfDelayed != PositionInvalid)
                    {
                        // Resolve delayed characters. This happens when
                        // there is BN in between of last strong and this NSM
                        ChangeType(characterClass,
                                    classIndex + startOfDelayed,
                                    counter -  startOfDelayed,
                                    characterClass[counter + classIndex]);

                        startOfDelayed = PositionInvalid;
                    }

                    break;

               case StateMachineAction.NSM_ET:
                   characterClass[counter + classIndex] = lastClass;
                   break;

               case StateMachineAction.N_ST:
                   Debug.Assert(startOfNeutrals == PositionInvalid,
                            "Cannot have unresolved neutrals. State: " +
                            state.ToString() + ", Class: " +
                            currentClass.ToString());

                   if (startOfDelayed != PositionInvalid)
                   {
                       startOfNeutrals = startOfDelayed;
                       startOfDelayed = PositionInvalid;
                   }
                   else
                   {
                       startOfNeutrals = counter;
                   }
                   lastClass = currentClass;
                   break;

               case StateMachineAction.N_ET:

                   // Note that this state is used for N_N as well.

                   if (startOfNeutrals == PositionInvalid)
                   {
                       if (startOfDelayed != PositionInvalid)
                       {
                           startOfNeutrals = startOfDelayed;
                       }
                   }
                   startOfDelayed = PositionInvalid;
                   lastClass = currentClass;
                   break;
                };

                // Fetch next state.

                state = NextState[(int)state, (int)currentClass];

                lengthResolved = Math.Max(startOfNeutrals, startOfDelayed) == PositionInvalid ?
                                 counter + 1 :
                                 ((Math.Min(startOfNeutrals, startOfDelayed) == PositionInvalid) ?
                                 (Math.Max(startOfNeutrals, startOfDelayed)) :
                                 (Math.Min(startOfNeutrals, startOfDelayed)));
            }


            // If the caller flagged this run as incomplete
            // return the maximun that we could resolve so far and the last strong (fixed)
            // class saved

            if (stateOut != null)
            {
                stateOut.LastStrongClass = lastStrongClass;
                stateOut.LastNumberClass = lastNumericClass;
                return lengthResolved;
            }

            // Else, resolve remaining neutrals or delayed classes.
            // Resolve as neutrals based on eor.

            else
            {

                if (lengthResolved != counter)

                ResolveNeutrals(characterClass,
                                classIndex + lengthResolved,
                                counter -  lengthResolved,
                                ArabicNumberAfterLeft ? DirectionClass.ArabicNumber : lastStrongClass,
                                eor,
                                runLevel);

                return counter;
            }
        }
示例#9
0
        static private void ChangeType(
            IList<DirectionClass> characterClass,   // [IN / OUT]
            int                   classIndex,
            int                   count,            // [IN]
            DirectionClass        newClass          // [IN]
        )
        {
            if ((characterClass == null) || (count == 0))
            {
                return;
            }

            for (int counter = 0; counter < count; counter++)
            {
                // We should never be changing a fixed type here

                Debug.Assert(CharProperty[2, (int) characterClass[counter + classIndex]]==0, "Changing class of a fixed class");
                characterClass[counter + classIndex] = newClass;
            }
        }
示例#10
0
        static private void ResolveNeutrals(
            IList<DirectionClass>   characterClass,   // [IN / OUT]
            int                     classIndex,       // [IN]
            int                     count,            // [IN]
            DirectionClass          startClass,       // [IN]
            DirectionClass          endClass,         // [IN]
            byte                    runLevel          // [IN]
        )
        {
            DirectionClass        startType;
            DirectionClass        endType;
            DirectionClass        resolutionType;

            if ((characterClass == null) || (count == 0))
            {
                return;
            }



            Debug.Assert(CharProperty[1, (int) startClass]==1 || (startClass == DirectionClass.ArabicLetter),
                     ("Cannot use non strong type to resolve neutrals"));

            Debug.Assert(CharProperty[1, (int) endClass]==1, ("Cannot use non strong type to resolve neutrals"));

            startType =  ((startClass == DirectionClass.EuropeanNumber) ||
                          (startClass == DirectionClass.ArabicNumber)   ||
                          (startClass == DirectionClass.ArabicLetter)) ? DirectionClass.Right : startClass;

            endType =  ((endClass == DirectionClass.EuropeanNumber) ||
                        (endClass == DirectionClass.ArabicNumber)   ||
                        (endClass == DirectionClass.ArabicLetter)) ? DirectionClass.Right : endClass;

            if (startType == endType)
            {
                resolutionType = startType;
            }
            else
            {
                resolutionType = Helper.IsOdd(runLevel) ? DirectionClass.Right : DirectionClass.Left;
            }

            for (int counter = 0; counter < count; counter++)
            {
                // We should never be changing a fixed type here

                Debug.Assert(CharProperty[2, (int) characterClass[counter + classIndex]]==0,
                         "Resolving fixed class as being neutral: " +
                         characterClass[counter + classIndex].ToString());

                characterClass[counter + classIndex] = resolutionType;
            }
        }
示例#11
0
        private  const int  MaxLevel                 = 63;         // right to left

        //
        //  Start BiDi class implementation
        //
        static private bool GetFirstStrongCharacter(
            CharacterBuffer     charBuffer,
            int                 ichText,
            int                 cchText,
            ref DirectionClass  strongClass)
        {
            DirectionClass currentClass = DirectionClass.ClassInvalid;

            int  counter = 0;
            int wordCount;

            while (counter<cchText)
            {
                int intChar = charBuffer[ichText + counter];
                wordCount = 1;
                if ((intChar & 0xFC00) == 0xD800)
                {
                    intChar = DoubleWideChar.GetChar(charBuffer, ichText, cchText, counter, out wordCount);
                }

                currentClass = Classification.CharAttributeOf((int) Classification.GetUnicodeClass(intChar)).BiDi;

                if (CharProperty[0, (int) currentClass]==1 || currentClass == DirectionClass.ParagraphSeparator)
                {
                    break;
                }
                counter +=  wordCount;
            }

            if (CharProperty[0, (int) currentClass]==1)
            {
                strongClass = currentClass;
                return true;
            }
            return false;
        }
示例#12
0
        /// <summary>
        /// GetLastStongAndNumberClass is used to get the last strong character class and last number
        /// class. if numberClass is not equal DirectionClass.ClassInvalid then we are interested in
        /// last strong class only otherwise we are interested in both last strong and number class.
        /// this method is useful while implementing the derived Bidi.State properties Bidi.LastNumberClass
        /// and Bidi.LastStrongClass.
        /// </summary>
        static internal bool GetLastStongAndNumberClass(
            CharacterBufferRange charString,
            ref DirectionClass   strongClass,
            ref DirectionClass   numberClass)
        {
            int             wordCount;
            DirectionClass  currentClass;
            int             i = charString.Length - 1;

            while (i >= 0)
            {
                int intChar = charString[i];
                wordCount = 1;

                if (((charString[i] & 0xFC00) == 0xDC00) && (i > 0) &&  ((charString[i-1] & 0xFC00) == 0xD800))
                {
                    intChar = (((charString[i-1] & 0x03ff) << 10) | (charString[i] & 0x3ff)) + 0x10000;
                    wordCount = 2;
                }

                currentClass = Classification.CharAttributeOf((int) Classification.GetUnicodeClass(intChar)).BiDi;

                // Stop scaning backwards in this character buffer once and ParagraphSeperator is encountered. 
                // Bidi algorithm works strictly within a paragraph. 
                if (currentClass == DirectionClass.ParagraphSeparator)
                {                    
                    return false; // stop scaning as paragraph separator is encountered before seeing last strong/number.
                }                
            
                if (CharProperty[1, (int) currentClass] == 1)
                {
                    if (numberClass == DirectionClass.ClassInvalid )
                    {   
                        numberClass = currentClass;                       
                    }
                    
                    if (currentClass != DirectionClass.EuropeanNumber)
                    {
                        strongClass = currentClass;
                        break;
                    }
                }
                i -= wordCount;
            }

            return true; // Finish scanning all the input characters 
        }
示例#13
0
        /// <Remark>
        /// Analyze() is created to serve the testing only. it is protected by security attribute to insure
        /// that BidiTest application only can call this method. the public key in the security attribute is
        /// generated from the BidiTest assembly by the command "sn -Tp biditest.exe"
        /// </Remark>
        static public bool Analyze(
            char []         chars,              // input text to be analyzed
            int             cchText,            // number of input char
            int             cchTextMaxHint,     // hint maximum number of char processed
            Flags           flags,              // control flags
            State           state,              // bidi state in, out or both
            out byte[]      levels,             // resolved level per char
            out int         cchResolved         // number of char resolved
            )
        {
            DirectionClass[] characterClass = new DirectionClass[cchText];
            levels = new byte[cchText];
            

            return Bidi.BidiAnalyzeInternal(
                new CharArrayCharacterBuffer(chars),
                0,
                cchText,
                cchTextMaxHint,
                flags,
                state,
                levels,
                new PartialArray<DirectionClass>(characterClass),
                out cchResolved
                );
        }
        /// <summary>
        /// Makes the Rover wait if it tries to move out of the plateau borders, else returns new Coordinates to move
        /// </summary>
        /// <param name="currentCoordinates">Rover's current coordinates</param>
        /// <param name="currentDirection">Rover's current direction</param>
        /// <returns>New Coordinates to move according to given direction</returns>
        public override Coordinates MoveToNewCoordinates(Coordinates currentCoordinates, DirectionClass currentDirection)
        {
            Coordinates newCoordinates = currentCoordinates + currentDirection.GetMoveForwardCoordinates();

            if (newCoordinates.coordX < lowerBoundryBorderCoordinates.coordX)
            {
                newCoordinates.coordX = lowerBoundryBorderCoordinates.coordX;
            }
            if (newCoordinates.coordX > upperBoundryBorderCoordinates.coordX)
            {
                newCoordinates.coordX = upperBoundryBorderCoordinates.coordX;
            }
            if (newCoordinates.coordY < lowerBoundryBorderCoordinates.coordY)
            {
                newCoordinates.coordY = lowerBoundryBorderCoordinates.coordY;
            }
            if (newCoordinates.coordY > upperBoundryBorderCoordinates.coordY)
            {
                newCoordinates.coordY = upperBoundryBorderCoordinates.coordY;
            }

            return(newCoordinates);
        }