private static GamePlayerBenchmark.SampleState SelectOrCreateChildAtRandom(Random r, GraphicalModel model, int[] variables, int[] variableSizes, IList <GamePlayerBenchmark.SampleState> children, ConcatVector[] humanFeatureVectors)
        {
            int i           = r.NextInt(variables.Length);
            int variable    = variables[i];
            int observation = r.NextInt(variableSizes[i]);

            foreach (GamePlayerBenchmark.SampleState s in children)
            {
                if (s.variable == variable && s.observation == observation)
                {
                    return(s);
                }
            }
            int humanObservationVariable = 0;

            foreach (GraphicalModel.Factor f in model.factors)
            {
                foreach (int j in f.neigborIndices)
                {
                    if (j >= humanObservationVariable)
                    {
                        humanObservationVariable = j + 1;
                    }
                }
            }
            GraphicalModel.Factor f_1 = model.AddFactor(new int[] { variable, humanObservationVariable }, new int[] { variableSizes[i], variableSizes[i] }, null);
            model.factors.Remove(f_1);
            GamePlayerBenchmark.SampleState newState = new GamePlayerBenchmark.SampleState(f_1, variable, observation);
            children.Add(newState);
            return(newState);
        }
        //////////////////////////////////////////////////////////////
        // This is an implementation of something like MCTS, trying to take advantage of the general speed gains due to fast
        // CliqueTree caching of dot products. It doesn't actually do any clever selection, preferring to select observations
        // at random.
        //////////////////////////////////////////////////////////////
        private static void Gameplay(Random r, GraphicalModel model, ConcatVector weights, ConcatVector[] humanFeatureVectors)
        {
            IList <int> variablesList     = new List <int>();
            IList <int> variableSizesList = new List <int>();

            foreach (GraphicalModel.Factor f in model.factors)
            {
                for (int i = 0; i < f.neigborIndices.Length; i++)
                {
                    int j = f.neigborIndices[i];
                    if (!variablesList.Contains(j))
                    {
                        variablesList.Add(j);
                        variableSizesList.Add(f.featuresTable.GetDimensions()[i]);
                    }
                }
            }
            int[] variables     = variablesList.Stream().MapToInt(null).ToArray();
            int[] variableSizes = variableSizesList.Stream().MapToInt(null).ToArray();
            IList <GamePlayerBenchmark.SampleState> childrenOfRoot = new List <GamePlayerBenchmark.SampleState>();
            CliqueTree tree           = new CliqueTree(model, weights);
            int        initialFactors = model.factors.Count;
            // Run some "samples"
            long start         = Runtime.CurrentTimeMillis();
            long marginalsTime = 0;

            for (int i_1 = 0; i_1 < 1000; i_1++)
            {
                log.Info("\tTaking sample " + i_1);
                Stack <GamePlayerBenchmark.SampleState> stack = new Stack <GamePlayerBenchmark.SampleState>();
                GamePlayerBenchmark.SampleState         state = SelectOrCreateChildAtRandom(r, model, variables, variableSizes, childrenOfRoot, humanFeatureVectors);
                long localMarginalsTime = 0;
                // Each "sample" is 10 moves deep
                for (int j = 0; j < 10; j++)
                {
                    // log.info("\t\tFrame "+j);
                    state.Push(model);
                    System.Diagnostics.Debug.Assert((model.factors.Count == initialFactors + j + 1));
                    ///////////////////////////////////////////////////////////
                    // This is the thing we're really benchmarking
                    ///////////////////////////////////////////////////////////
                    if (state.cachedMarginal == null)
                    {
                        long s = Runtime.CurrentTimeMillis();
                        state.cachedMarginal = tree.CalculateMarginalsJustSingletons();
                        localMarginalsTime  += Runtime.CurrentTimeMillis() - s;
                    }
                    stack.Push(state);
                    state = SelectOrCreateChildAtRandom(r, model, variables, variableSizes, state.children, humanFeatureVectors);
                }
                log.Info("\t\t" + localMarginalsTime + " ms");
                marginalsTime += localMarginalsTime;
                while (!stack.Empty())
                {
                    stack.Pop().Pop(model);
                }
                System.Diagnostics.Debug.Assert((model.factors.Count == initialFactors));
            }
            log.Info("Marginals time: " + marginalsTime + " ms");
            log.Info("Avg time per marginal: " + (marginalsTime / 200) + " ms");
            log.Info("Total time: " + (Runtime.CurrentTimeMillis() - start));
        }