예제 #1
0
        /// <summary>
        /// Initializes a new <see cref="GameLevel"/> instance with the specified lists of vertices
        /// and line segments, and resets the vertices' positions if requested.
        /// </summary>
        /// <param name="vertices">An enumeration of vertices.</param>
        /// <param name="lineSegments">An enumeration of line segments.</param>
        /// <param name="resetPositions">Specifies whether the vertices' positions should be reset,
        /// arranging all vertices in a circle in random order.</param>
        private GameLevel(
            IEnumerable<Vertex> vertices,
            IEnumerable<LineSegment> lineSegments,
            bool resetPositions)
        {
            _vertices = vertices.ToArray();
            _lineSegments = lineSegments.ToArray();
            _intersections = new Dictionary<LineSegment, HashSet<LineSegment>>();
            foreach (LineSegment lineSegment in _lineSegments)
            {
                _intersections[lineSegment] = new HashSet<LineSegment>();
            }
            _draggedVertex = null;
            _intersectionCount = 0;

            if (resetPositions)
            {
                while (_intersectionCount == 0)
                {
                    ResetVertexPositions();
                    CalculateAllIntersections();
                }
            }
            else
                CalculateAllIntersections();
        }
예제 #2
0
        /// <summary>
        /// Changes the current state of a vertex and possibly the states of vertices which are
        /// directly connected to it and line segments which are attached to it.
        /// </summary>
        /// <param name="vertex">The vertex whose state should be changed.</param>
        /// <param name="state">The new state of the vertex.</param>
        private void ChangeVertexState(Vertex vertex, VertexState state)
        {
            VertexState oldState = vertex.State;
            vertex.State = state;

            if (state == VertexState.Dragged || state == VertexState.UnderMouse)
            {
                if (oldState != VertexState.Dragged && oldState != VertexState.UnderMouse)
                {
                    // The vertex was neither under the mouse, nor was it being dragged by the
                    // user, but now either of those events has occurred
                    foreach (Vertex connectedVertex in vertex.ConnectedVertices)
                    {
                        connectedVertex.State = VertexState.ConnectedToHighlighted;
                    }
                    foreach (LineSegment lineSegment in vertex.LineSegments)
                    {
                        lineSegment.State = LineSegmentState.Highlighted;
                    }
                }
            }
            else if (oldState == VertexState.Dragged || oldState == VertexState.UnderMouse)
            {
                // The vertex was under the mouse or was being dragged by the user, but
                // that is no longer the case
                foreach (Vertex connectedVertex in vertex.ConnectedVertices)
                {
                    connectedVertex.State = VertexState.Normal;
                }
                foreach (LineSegment lineSegment in vertex.LineSegments)
                {
                    lineSegment.State = (_intersections[lineSegment].Count > 0
                                            ? LineSegmentState.Intersected
                                            : LineSegmentState.Normal);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Identifies any changes in the intersections between line segments attached to a
        /// specific vertex and any line segments in the game level, after that vertex has been
        /// dragged to a new position.
        /// </summary>
        /// <param name="vertex">The vertex which has been dragged to a new position.</param>
        /// <remarks>
        /// <para>The a single vertex has been dragged to a new position, only the intersections
        /// of the line segments attached to it might have changed, so it is unnecessary to
        /// recalculate all intersections in the game level.</para>
        /// </remarks>
        private void RecalculateIntersectionsForVertex(Vertex vertex)
        {
            foreach (LineSegment lineSegment in vertex.LineSegments)
            {
                HashSet<LineSegment> intersectingSegments = _intersections[lineSegment];
                foreach (LineSegment otherSegment in _lineSegments)
                {
                    if (otherSegment == lineSegment)
                        continue;

                    if (CalculationHelper.CheckLinesIntersect(
                        lineSegment.Point1,
                        lineSegment.Point2,
                        otherSegment.Point1,
                        otherSegment.Point2))
                    {
                        if (!intersectingSegments.Contains(otherSegment))
                            AddIntersection(lineSegment, otherSegment);
                    }
                    else if (intersectingSegments.Contains(otherSegment))
                        RemoveIntersection(lineSegment, otherSegment);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Sets the vertex which is currently under the mouse cursor.
        /// </summary>
        /// <param name="vertex">The vertex which is currently under the mouse cursor.</param>
        public void SetVertexUnderMouse(Vertex vertex)
        {
            if (_vertexUnderMouse == vertex)
                return;

            if (_vertexUnderMouse != null && !IsDragging)
                ChangeVertexState(_vertexUnderMouse, VertexState.Normal);

            _vertexUnderMouse = vertex;
            if (_vertexUnderMouse != null && !IsDragging)
                ChangeVertexState(_vertexUnderMouse, VertexState.UnderMouse);
        }
예제 #5
0
 /// <summary>
 /// Initiates the dragging of a specified vertex requested by the user.
 /// </summary>
 /// <param name="draggedVertex">The vertex which should be dragged.</param>
 public void StartDrag(Vertex draggedVertex)
 {
     _draggedVertex = draggedVertex;
     _draggedVertex.State = VertexState.Dragged;
 }
예제 #6
0
        /// <summary>
        /// Completes the dragging of the vertex which is currently being dragged, and
        /// recalculates all current and potential intersections which might have been affected by
        /// the dragging.
        /// </summary>
        public void FinishDrag()
        {
            ChangeVertexState(_draggedVertex, VertexState.Normal);
            RecalculateIntersectionsForVertex(_draggedVertex);
            _draggedVertex = null;

            if (_vertexUnderMouse != null)
                ChangeVertexState(_vertexUnderMouse, VertexState.UnderMouse);

            if (_intersectionCount == 0)
                OnLevelSolved();
        }
예제 #7
0
        /// <summary>
        /// Creates a new <see cref="GameLevel"/> instance from an enumeration of vertices
        /// generated by a <see cref="Generation.LevelGenerator"/> instance.
        /// </summary>
        /// <param name="generatedVertices">An enumeration of vertices generated by the game level
        /// generator.</param>
        /// <returns>The created game level instance.</returns>
        /// <remarks>
        /// <para>The generated vertices are automatically arranged in a circle in random order
        /// during the game level's initialization.</para>
        /// </remarks>
        public static GameLevel Create(IEnumerable<Generation.Vertex> generatedVertices)
        {
            var vertexMappings = new Dictionary<Generation.Vertex, Vertex>();
            var lineSegments = new List<LineSegment>();
            foreach (Generation.Vertex generatedVertex in generatedVertices)
            {
                var vertex = new Vertex();
                vertexMappings[generatedVertex] = vertex;
                foreach (Generation.Vertex connectedGeneratedVertex in generatedVertex.ConnectedVertices)
                {
                    if (!vertexMappings.ContainsKey(connectedGeneratedVertex))
                    {
                        // The connected vertex has not been mapped to a vertex view model yet;
                        // skip this line segment for now, it will be added when the other vertex
                        // is enumerated
                        continue;
                    }

                    Vertex otherVertex = vertexMappings[connectedGeneratedVertex];
                    LineSegment lineSegment = vertex.ConnectToVertex(otherVertex);
                    lineSegments.Add(lineSegment);
                }
            }

            return new GameLevel(vertexMappings.Values, lineSegments, true);
        }
예제 #8
0
        /// <summary>
        /// Creates a new <see cref="GameLevel"/> instance from an enumeration of vertices loaded
        /// from a saved game file.
        /// </summary>
        /// <param name="savedVertices">An enumeration of vertices loaded from the saved game file.
        /// </param>
        /// <returns>The created game level instance.</returns>
        /// <remarks>
        /// <para>The loaded vertices' positions are preserved during the game level's
        /// initialization.</para>
        /// </remarks>
        public static GameLevel Create(IEnumerable<Saves.Vertex> savedVertices)
        {
            var vertexMappings = new Dictionary<int, Vertex>();
            var lineSegments = new List<LineSegment>();
            foreach (Saves.Vertex savedVertex in savedVertices)
            {
                var vertex = new Vertex();
                vertex.SetPosition(new Point(savedVertex.X, savedVertex.Y));
                vertexMappings[savedVertex.Id] = vertex;
                foreach (int connectedVertexId in savedVertex.ConnectedVertexIds)
                {
                    if (!vertexMappings.ContainsKey(connectedVertexId))
                    {
                        // The connected vertex has not been mapped to a vertex view model yet;
                        // skip this line segment for now, it will be added when the other vertex
                        // is enumerated
                        continue;
                    }

                    Vertex otherVertex = vertexMappings[connectedVertexId];
                    LineSegment lineSegment = vertex.ConnectToVertex(otherVertex);
                    lineSegments.Add(lineSegment);
                }
            }

            return new GameLevel(vertexMappings.Values, lineSegments, false);
        }
예제 #9
0
        /// <summary>
        /// Connects the vertex to another vertex with a line segment and returns it.
        /// </summary>
        /// <param name="otherVertex">The vertex which should be connected to the current one.
        /// </param>
        /// <returns>The created line segment between the two vertices.</returns>
        /// <exception cref="InvalidOperationException">
        /// An attempt is made to connect the vertex to itself.
        /// 
        /// -or-
        /// A line segment between the two vertices already exists.
        /// </exception>
        public LineSegment ConnectToVertex(Vertex otherVertex)
        {
            if (this == otherVertex)
                throw new InvalidOperationException("A vertex cannot be connected to itself.");
            if (_lineSegmentsMap.ContainsKey(otherVertex))
            {
                throw new InvalidOperationException(
                    "A line segment between the two vertices already exists.");
            }

            var lineSegment = new LineSegment(this, otherVertex);
            _lineSegmentsMap[otherVertex] = lineSegment;
            otherVertex._lineSegmentsMap[this] = lineSegment;
            return lineSegment;
        }
예제 #10
0
 /// <summary>
 /// Initializes a new <see cref="LineSegment"/> instance with the specified two endpoint
 /// vertices.
 /// </summary>
 /// <param name="vertex1">The vertex at the first endpoint of the line segment.</param>
 /// <param name="vertex2">The vertex at the second endpoint of the line segment.</param>
 public LineSegment(Vertex vertex1, Vertex vertex2)
 {
     _vertex1 = vertex1;
     _vertex2 = vertex2;
 }