Esempio n. 1
0
        /// <summary>
        /// Finds valid neighbors for a node.
        /// Only considers 4 directions (up/down/left/right).  Could be updated to allow for diagonal movement,
        /// however that is currently not supported.
        /// </summary>
        public IEnumerable <OfficeNode> GetNeighbors(OfficeNode currentNode)
        {
            int myRow    = currentNode.MatrixRow;
            int myColumn = currentNode.MatrixColumn;

            // Are we within bounds to start?
            if (OutOfBounds(myRow, myColumn))
            {
                return(new List <OfficeNode>(0));
            }

            // Maximum of 4 neighbors are possible.  (Diagonal movement would increase to 8)
            List <OfficeNode> neighbors = new List <OfficeNode>(4);

            // Only find immediate neighbors, which fall within the bounds of the matrix
            if (!OutOfBounds(myRow - 1, myColumn))             // up
            {
                neighbors.Add(GetPopulateNode(myRow - 1, myColumn));
            }
            if (!OutOfBounds(myRow, myColumn - 1))             // left
            {
                neighbors.Add(GetPopulateNode(myRow, myColumn - 1));
            }
            if (!OutOfBounds(myRow, myColumn + 1))             // right
            {
                neighbors.Add(GetPopulateNode(myRow, myColumn + 1));
            }
            if (!OutOfBounds(myRow + 1, myColumn))             // down
            {
                neighbors.Add(GetPopulateNode(myRow + 1, myColumn));
            }

            return(neighbors);
        }
Esempio n. 2
0
        /// <summary>
        /// Describes the layout of an office, and provides functionality for finding the closest coffee machine.
        /// </summary>
        /// <param name="rows">Total number of rows in the office layout.</param>
        /// <param name="columns">Total number of columns in the office layout.</param>
        /// <param name="origin">The origin location (desk) from which the coffee search will begin.</param>
        /// <param name="coffeeMachines">Coordinate pairs for all coffee machines in the office.</param>
        /// <param name="walls">Coordinate pairs for all walls in the office.</param>
        public OfficeLayout(int rows, int columns, Tuple <int, int> origin, List <Tuple <int, int> > coffeeMachines, List <Tuple <int, int> > walls)
        {
            Rows    = rows;
            Columns = columns;
            Origin  = new OfficeNode(origin, OfficeLocationType.Desk, true /*isOrigin*/);

            // Initialize matrix to hold nodes
            OfficeMap = new OfficeNode[rows, columns];

            // Set origin desk
            OfficeMap[Origin.MatrixRow, Origin.MatrixColumn] = Origin;

            // Add coffee machines
            foreach (Tuple <int, int> coffeeMachine in coffeeMachines)
            {
                OfficeNode coffeeNode = new OfficeNode(coffeeMachine, OfficeLocationType.Coffee);
                OfficeMap[coffeeNode.MatrixRow, coffeeNode.MatrixColumn] = coffeeNode;
            }

            // Add walls
            foreach (Tuple <int, int> wall in walls)
            {
                OfficeNode wallNode = new OfficeNode(wall, OfficeLocationType.Wall);
                OfficeMap[wallNode.MatrixRow, wallNode.MatrixColumn] = wallNode;
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Tests that a few basic pieces of OfficeNodes work correctly.
        /// </summary>
        public static void TestOfficeNode()
        {
            bool result = false;

            var        nodeLocation = new Tuple <int, int>(2, 1);
            OfficeNode officeNode   = new OfficeNode(nodeLocation);

            result = officeNode.LocationType == OfficeLocationType.Desk;
            PrintTestResult("Desk node correctly set by default.", result, OfficeLocationType.Desk.ToString(), officeNode.LocationType.ToString());

            result = officeNode.MatrixRow == nodeLocation.Item1 - 1;
            PrintTestResult("Matrix row matches expectation.", result, (nodeLocation.Item1 - 1).ToString(), officeNode.MatrixRow.ToString());

            result = officeNode.MatrixColumn == nodeLocation.Item2 - 1;
            PrintTestResult("Matrix column matches expectation.", result, (nodeLocation.Item2 - 1).ToString(), officeNode.MatrixColumn.ToString());

            result = officeNode.IsOrigin == false;
            PrintTestResult("Node is not set as origin by default.", result, bool.FalseString, officeNode.IsOrigin.ToString());

            result = officeNode.State == OfficeLocationState.NotVisited;
            PrintTestResult("Node state is NotVisited by default.", result, OfficeLocationState.NotVisited.ToString(), officeNode.State.ToString());

            officeNode = new OfficeNode(nodeLocation, OfficeLocationType.Coffee, true);

            result = officeNode.LocationType == OfficeLocationType.Coffee;
            PrintTestResult("Location type is correctly set.", result, OfficeLocationType.Coffee.ToString(), officeNode.LocationType.ToString());

            result = officeNode.IsOrigin == true;
            PrintTestResult("Origin node is correctly set.", result, bool.TrueString, officeNode.IsOrigin.ToString());
        }
Esempio n. 4
0
        /// <summary>
        /// Retraces the solution path, to get the visited nodes which lead directly to the destination.
        /// Used for "could be interesting to know" purposes only.
        /// </summary>
        private IEnumerable <OfficeNode> RetracePath(OfficeNode endNode)
        {
            OfficeNode currentNode        = endNode;
            ICollection <OfficeNode> path = new List <OfficeNode>();

            while (currentNode != null)
            {
                path.Add(GetNode(currentNode.MatrixRow, currentNode.MatrixColumn));
                currentNode = currentNode.PreviousNode;
            }
            return(path);
        }
Esempio n. 5
0
        /// <summary>
        /// Compares the current node with the end state
        /// </summary>
        /// <param name="currentNode">Node to inspect</param>
        /// <returns>True if the specified node is a coffee machine (or alternatively, equals the destination)</returns>
        public bool IsCoffeeMachine(OfficeNode currentNode)
        {
            if (currentNode == null)
            {
                return(false);
            }

            return(currentNode.LocationType == OfficeLocationType.Coffee);

            // TODO: remove if no longer using
            //return currentNode.Equals(Destination);
        }
Esempio n. 6
0
        /// <summary>
        /// Searches an office layout map to find the distance to the nearest accessible coffee machine,
        /// if it exists.
        /// </summary>
        /// <returns>Distance (in matrix squares) from the Origin location to the closest coffee machine.  If no accessible machines
        /// are found, or OfficeMap is not initialized, returns PathError.</returns>
        public int FindCoffeeDistance()
        {
            if (OfficeMap == null)
            {
                return(Constants.PathError);
            }

            // Create queue for holding nodes we want to visit
            Queue <OfficeNode> walkingQueue = new Queue <OfficeNode>();

            // Set state of origin to get things started
            Origin.Distance     = 0;
            Origin.PreviousNode = null;
            Origin.State        = OfficeLocationState.Queued;
            walkingQueue.Enqueue(Origin);

            while (walkingQueue.Count > 0)
            {
                OfficeNode visitNode = walkingQueue.Dequeue();

                if (IsCoffeeMachine(visitNode))
                {
                    // TODO: Use this to output the path taken? Could be interesting.
                    IEnumerable <OfficeNode> walkedPath = RetracePath(visitNode);
                    PrintOptimalPath(walkedPath);

                    // We are done, return distance traveled to reach this node
                    return(visitNode.Distance);
                }

                // Check neighbors to this node, and consider adding to the queue
                foreach (OfficeNode neighborNode in GetNeighbors(visitNode))
                {
                    // Don't revisit nodes, and don't bother queuing walls
                    if (neighborNode.State == OfficeLocationState.NotVisited && neighborNode.LocationType != OfficeLocationType.Wall)
                    {
                        neighborNode.State        = OfficeLocationState.Queued;
                        neighborNode.PreviousNode = visitNode;
                        neighborNode.Distance     = visitNode.Distance + 1;
                        walkingQueue.Enqueue(neighborNode);
                    }
                }

                visitNode.State = OfficeLocationState.Visited;
            }

            // No accessible coffee machines found
            return(Constants.PathError);
        }
Esempio n. 7
0
        /// <summary>
        /// Override function for equals. Compares coordinates and location type to determine equality.
        ///
        /// Used in an early rendition of the code to find a specific point in an office layout. Useful for
        /// expanded functionality in that direction, otherwise consider removing.
        /// </summary>
        /// <param name="obj">The object to compare to.</param>
        /// <returns>True if the OfficeNodes are equal, otherwise false.</returns>
        public override bool Equals(object obj)
        {
            OfficeNode officeNode = obj as OfficeNode;

            if (officeNode == null)
            {
                return(false);
            }

            if (ReferenceEquals(officeNode, this))
            {
                return(true);
            }

            return(officeNode.Coordinates.Equals(Coordinates) && officeNode.LocationType.Equals(LocationType));
        }
Esempio n. 8
0
        /// <summary>
        /// Gets the specified node, and creates one if it doesn't exist.
        /// If the specified node does not exist, and is a valid location, a new node is created
        /// for the specified coordinates, and is added to the map as a desk.
        /// Since desk locations are implied, not supplied, this provides a lazy addition of desk locations.
        /// </summary>
        /// <param name="row">Row of the node to retrieve.</param>
        /// <param name="column">Column of the node to retrieve.</param>
        /// <returns>The specified node.  If it does not exist, it is created.</returns>
        public OfficeNode GetPopulateNode(int row, int column)
        {
            if (OutOfBounds(row, column))
            {
                // Throw instead?
                return(null);
            }

            if (OfficeMap[row, column] != null)
            {
                return(OfficeMap[row, column]);
            }

            // Since we are not supplied the location of all the desks to start, create a desk at any empty location
            OfficeNode tempNode = new OfficeNode(new Tuple <int, int>(row + 1, column + 1), OfficeLocationType.Desk);

            OfficeMap[row, column] = tempNode;
            return(tempNode);
        }