private void PerftHelper(Grid grid, int depth, int maxDepth, int[] results,
            HashSet<ulong> visitedStates)
        {
            int player = depth & 1;

            if (depth >= maxDepth || grid.IsGameOver(player)
                || visitedStates.Contains(grid.Hash))
            {
                return;
            }

            results[depth]++;
            visitedStates.Add(grid.Hash);

            for (int i = 0; i < grid.Width; i++)
            {
                if (grid.IsValidMove(i))
                {
                    grid.Move(i, player);
                    PerftHelper(grid, depth + 1, maxDepth, results, visitedStates);
                    grid.UndoMove(i, player);
                }
            }
        }
        public void IsGameOverVerticalTest()
        {
            Grid grid = new Grid(width, height, seed);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(0, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(0, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(0, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(0, 0);
            Assert.AreEqual(0, grid.IsGameOver());
            Assert.AreEqual(true, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));

            grid = new Grid(width, height, seed);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(width - 1, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(width - 1, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(width - 1, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(width - 1, 1);
            Assert.AreEqual(1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(true, grid.IsGameOver(1));

            grid = new Grid(width, height, seed);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(3, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(4, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(3, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(4, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(3, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(4, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(4, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(3, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(0, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(1, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(2, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(5, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(1, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(5, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(1, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(5, 1);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(1, 0);
            Assert.AreEqual(-1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(false, grid.IsGameOver(1));
            grid.Move(5, 1);
            Assert.AreEqual(1, grid.IsGameOver());
            Assert.AreEqual(false, grid.IsGameOver(0));
            Assert.AreEqual(true, grid.IsGameOver(1));
        }