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); }
public abstract Coordinates MoveToNewCoordinates(Coordinates currentCoordinates, DirectionClass currentDirection);
/// <summary> /// Turns the Rover 90 degrees to right /// </summary> public void TurnRight() { currentDirection = currentDirection.GetRightDirection(); }
/// <summary> /// Turns the Rover 90 degrees to left /// </summary> public void TurnLeft() { currentDirection = currentDirection.GetLeftDirection(); }
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; } }
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; } }
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; } }
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; }
/// <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 }
/// <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); }