// Removes the wall between 2 cells by looking a their cornerPoints
    // Once the common corner points are found, we set them as "non-neighbours"
    public void RemoveBorderBetweenCells(GraphVertex otherGraphVertex)
    {
        RegularCell otherCell = (RegularCell)otherGraphVertex;

        foreach (RegularCell c in this.connectedCells)
        {
            // We look for the adjacent cell to remove the border
            if (c.Equals(otherCell))
            {
                // We look for the corner points which are common to the two cells
                List <Vertex> commonVertices = new List <Vertex> ();
                foreach (Vertex v1 in this.cornerPoints)
                {
                    foreach (Vertex v2 in otherCell.cornerPoints)
                    {
                        if (v1.Equals(v2))
                        {
                            commonVertices.Add(v1);
                        }
                    }
                }

                // We disconnect all the border points which are common to the 2 cells so that the way is open
                foreach (Vertex v1 in commonVertices)
                {
                    foreach (Vertex v2 in commonVertices)
                    {
                        v1.RemoveNeighbour(v2);
                    }
                }
            }
        }
    }
    // Connects 2 cells (connects the corner points each other and the cores)
    public void ConnectToOtherGraphVertex(GraphVertex other)
    {
        RegularCell otherCell = (RegularCell)other;

        List <Pair <Vertex> > pairList = new List <Pair <Vertex> > ();
        float delta = 0.2f;

        foreach (Vertex v1 in this.cornerPoints)
        {
            foreach (Vertex v2 in otherCell.cornerPoints)
            {
                if (Vector2.Distance(v1.Coo, v2.Coo) < delta)
                {
                    Pair <Vertex> pair = new Pair <Vertex> (v1, v2);
                    if (!pair.AlreadyExists(pairList))
                    {
                        pairList.Add(pair);
                    }
                }
            }
        }

        Debug.Assert(pairList.Count == 2);

        foreach (Pair <Vertex> p in pairList)
        {
            // Fusion of the pair elements and their respective neighborhood
            foreach (Vertex v in p.Ext1.Neighbours.ToArray())
            {
                // We add our neighbours to the other corner point
                p.Ext2.AddNeighbour(v);
            }
            // Replacement of the corner in our cell
            this.cornerPoints.Remove(p.Ext1);
            this.cornerPoints.Add(p.Ext2);
        }


        // Connection of the cores of each cells
        core.AddNeighbour(otherCell.core);
        otherCell.core.AddNeighbour(core);

        // Add to the connected cells lists
        if (!this.connectedCells.Contains(otherCell))
        {
            this.connectedCells.Add(otherCell);
        }
        if (!otherCell.connectedCells.Contains(this))
        {
            otherCell.connectedCells.Add(this);
        }
    }
    private Color teleportColor;               // color of the teleport (if any)


    // CONSTRUCTOR
    // Creates a cell without connected cell nor teleport connexion
    public RegularCell(Vector2 coreCoo, float cellSize, int nbBorders, float angleOffset)
    {
        this.core        = new Vertex(coreCoo);
        this.cellSize    = cellSize;
        this.nbBorders   = nbBorders;
        this.angleOffset = angleOffset;

        this.cornerPoints = new List <Vertex> ();
        for (int i = 0; i < nbBorders; i++)
        {
            float angle = i * 2 * Mathf.PI / nbBorders + angleOffset;
            cornerPoints.Add(new Vertex(coreCoo + cellSize * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle))));
        }
        ConnectCorners();

        this.connectedCells    = new List <RegularCell> ();
        this.teleportConnexion = null;
    }
    // Generates a grid of QuadCell
    public static IEnumerable <GraphVertex> GridCellUndirectedGraph(float cellSize, int nbLines, int nbColumns, int nbBorders, bool putTeleporters)
    {
        RegularCell[,] vertices = new RegularCell[nbLines, nbColumns];


        // Initialization of each cell
        for (int i = 0; i < nbLines; i++)
        {
            for (int j = 0; j < nbColumns; j++)
            {
                // For each cell, we calculate its center according to the grid
                // and the optional offsets due to the shape (square/hexagon) and the line number (odd or even)
                Pair <float> angleOffsets = UndirectedGraph.DetermineAngleOffsets(nbBorders);
                Pair <float> axisOffsets  = DetermineAxisOffsets(nbBorders, cellSize);

                float coreX = j * cellSize * 2 * Mathf.Cos(angleOffsets.Ext1);
                float coreY = i * cellSize * 2 * Mathf.Sin(angleOffsets.Ext2);

                coreY += axisOffsets.Ext2 * 2 * Mathf.Floor(i / 2);

                if (i % 2 == 0)
                {
                    coreX += axisOffsets.Ext1;
                    coreY += axisOffsets.Ext2;
                }
                else
                {
                    coreY += 2 * axisOffsets.Ext2;
                }

                Vector2 coreCoo = new Vector2(coreX, coreY);

                vertices [i, j] = new RegularCell(coreCoo, cellSize, nbBorders, angleOffsets.Ext1);
            }
        }

        // We define the number and random indexes of the teleporters
        List <Pair <int> > teleportersIndexes = new List <Pair <int> > ();

        if (putTeleporters)
        {
            // Sets the indexes of the cells with a teleporter and the number of pairs of teleporters
            int nbTeleporters = Mathf.FloorToInt(nbLines * nbColumns / 40);

            // Find the right amound of distinct indexes
            for (int k = 0; k < 2 * nbTeleporters; k++)
            {
                Pair <int> p = new Pair <int> (Random.Range(0, nbLines - 1), Random.Range(0, nbColumns - 1));

                while (p.OrderedValueExistsIn(teleportersIndexes))
                {
                    p = new Pair <int> (Random.Range(0, nbLines - 1), Random.Range(0, nbColumns - 1));
                }
                teleportersIndexes.Add(p);
            }

            // Add a teleporter in the data of the corresponding cells
            for (int k = 0; k < 2 * nbTeleporters; k += 2)
            {
                Pair <int> id1 = teleportersIndexes [k];
                Pair <int> id2 = teleportersIndexes [k + 1];

                vertices [id1.Ext1, id1.Ext2].TeleportCell = vertices [id2.Ext1, id2.Ext2];
                vertices [id2.Ext1, id2.Ext2].TeleportCell = vertices [id1.Ext1, id1.Ext2];

                Color c = Random.ColorHSV();
                vertices [id1.Ext1, id1.Ext2].TeleportColor = c;
                vertices [id2.Ext1, id2.Ext2].TeleportColor = c;
            }
        }

        // Connexion of cells each other (regardless of the walls)
        if (nbBorders == 4)
        {
            SquareConnections(vertices, nbLines, nbColumns, 4);
        }
        else
        {
            HexagonConnections(vertices, nbLines, nbColumns, 6);
        }

        // The cast to IEnumerable<GraphVertex> doesn't work, that's why I use the ArrayExtension class (cf end of file)
        return(ArrayExtensions.ToEnumerable <GraphVertex> (vertices));
    }