public Fuzzy MoveAlong(Direction direction, double step, out Position newPosition) { // simple case #1 : dx == 0 if ( direction.Dx == 0 ) { newPosition = new Position(x, y + step * Fuzzy.Sign(direction.Dy)); return step; } // simple case #2 : dy == 0 if ( direction.Dy == 0) { newPosition = new Position(x + step * Fuzzy.Sign(direction.Dx), y); return step; } var newXOnGrid = GetNextPositionOnGrid(x, direction.Dx, step); var newYOnGrid = GetNextPositionOnGrid(y, direction.Dy, step); var xMotion = newXOnGrid - x; var yMotion = newYOnGrid - y; Debug.Assert(Fuzzy.Abs(xMotion) > 0); Debug.Assert(Fuzzy.Abs(xMotion) <= 0.5); Debug.Assert(Fuzzy.Abs(yMotion) > 0); Debug.Assert(Fuzzy.Abs(yMotion) <= 0.5); // shorter motion on X axis if (xMotion / direction.Dx < yMotion / direction.Dy) { yMotion = xMotion * direction.Dy / direction.Dx; Debug.Assert(Fuzzy.Abs(yMotion) > 0); Debug.Assert(Fuzzy.Abs(yMotion) <= 0.5); } // shorter motion on Y axis else if (xMotion / direction.Dx > yMotion / direction.Dy) { xMotion = yMotion * direction.Dx / direction.Dy; Debug.Assert(Fuzzy.Abs(xMotion) > 0); Debug.Assert(Fuzzy.Abs(xMotion) <= 0.5); } Debug.Assert(yMotion / xMotion == direction.Dy / direction.Dx); newPosition = new Position(x + xMotion, y + yMotion); return Fuzzy.Sqrt(xMotion * xMotion + yMotion * yMotion); }
public bool SolveDirection(Direction direction) { var distance = new Fuzzy(0.0); var position = startPosition; Log("----"); while (true) { Log("(X ; Y) = ({0} ; {1})", position.X, position.Y); Log("(dX ; dY) = ({0} ; {1})", direction.Dx, direction.Dy); distance += position.MoveAlong(direction, step, out position); if (distance > maxDistance) { Log("Max distance reached"); return false; } if (position.Equals(startPosition)) { Log("Start position reached !!!"); return true; } bool reflectionOnX, reflectionOnY; var xOnGrid = Fuzzy.Floor(position.X); var yOnGrid = Fuzzy.Floor(position.Y); Log("(X ; Y) = ({0} ; {1})", position.X, position.Y); var isOnHorizontalGrid = position.Y == yOnGrid; var isOnVerticalGrid = position.X == xOnGrid; Log("isOnHorizontalGrid = {0}", isOnHorizontalGrid); Log("isOnVerticalGrid = {0}", isOnVerticalGrid); if (isOnHorizontalGrid && isOnVerticalGrid) { var mirrorOnUpperLeft = IsMirrorAt(position.X - step, position.Y - step); var mirrorOnUpperRight = IsMirrorAt(position.X + step, position.Y - step); var mirrorOnLowerLeft = IsMirrorAt(position.X - step, position.Y + step); var mirrorOnLowerRight = IsMirrorAt(position.X + step, position.Y + step); // we can't possibly be in the middle of 4 mirrors Debug.Assert(!(mirrorOnUpperLeft&&mirrorOnUpperRight&&mirrorOnLowerLeft&&mirrorOnLowerRight)); reflectionOnX = mirrorOnUpperLeft && mirrorOnLowerLeft || mirrorOnUpperRight && mirrorOnLowerRight; reflectionOnY = mirrorOnUpperLeft && mirrorOnUpperRight || mirrorOnLowerLeft && mirrorOnLowerRight; } else if (isOnHorizontalGrid) { var mirrorAbove = IsMirrorAt(position.X, position.Y - step); var mirrorBelow = IsMirrorAt(position.X, position.Y + step); reflectionOnY = mirrorAbove || mirrorBelow; reflectionOnX = false; } else if (isOnVerticalGrid) { var mirrorOnLeft = IsMirrorAt(position.X - step, position.Y); var mirrorOnRight = IsMirrorAt(position.X + step, position.Y); reflectionOnX = mirrorOnLeft || mirrorOnRight; reflectionOnY = false; } else if (IsMirrorAt(position.X, position.Y)) { Log("ray is destroyed"); return false; } else { reflectionOnY = false; reflectionOnX = false; } if (position.X <= 1 || position.X >= grid.GetLength(0) - 1) Debug.Assert(reflectionOnX); if (position.Y <= 1 || position.Y >= grid.GetLength(1) - 1) Debug.Assert(reflectionOnY); if (reflectionOnX) Log("reflection on Y"); if (reflectionOnY) Log("reflection on Y"); direction = new Direction( direction.Dx * (reflectionOnX ? -1 : 1), direction.Dy * (reflectionOnY ? -1 : 1)); } }