Example #1
0
 protected override double CalculateValue(SimulationState state, int pieceIndex, PieceDefinition piece)
 {
     return(_calculator.CalculateValueOfPurchasing(state, pieceIndex, piece));
 }
        //https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning#Pseudocode
        private int AlphaBeta(SimulationState parentState)
        {
            var maximizingPlayer = parentState.ActivePlayer;
            int alpha            = int.MinValue;
            int beta             = int.MaxValue;

            int bestMove  = -1;
            int bestValue = Int32.MinValue;

            //0-2 + -1 for advance
            var possibleMoves       = new FixedArray4Int();
            var possibleMoveValues  = new FixedArray4Double();
            int possibleMovesAmount = 0;

            //Insertion sort the possible moves in to possibleMoves(Weights)
            //Buying stuff
            for (var i = 0; i < 3; i++)
            {
                var piece = Helpers.GetNextPiece(parentState, i);
                if (Helpers.ActivePlayerCanPurchasePiece(parentState, piece))
                {
                    var value = _calculator.CalculateValueOfPurchasing(parentState, parentState.NextPieceIndex + i, piece);
                    InsertionSort(ref possibleMoves, ref possibleMoveValues, ref possibleMovesAmount, i, value);
                }
            }
            //Advance
            {
                var value = _calculator.CalculateValueOfAdvancing(parentState);
                InsertionSort(ref possibleMoves, ref possibleMoveValues, ref possibleMovesAmount, -1, value);
            }

            //foreach child
            var state = _thisThreadPool.Get();

            for (var m = 0; m < possibleMovesAmount; m++)
            {
                var move = possibleMoves[m];

                if (beta <= alpha && move != -1)
                {
                    continue;
                }

                parentState.CloneTo(state);
                if (_placementMaker == null)
                {
                    state.Fidelity = SimulationFidelity.NoPiecePlacing;
                }

                int v;
                if (move == -1)
                {
                    state.PerformAdvanceMove();
                    if (_placementMaker != null)
                    {
                        while (state.PieceToPlace != null)
                        {
                            _placementMaker.PlacePiece(state);
                        }
                    }

                    //Decrease alpha by 1 (if possible) so we can identify draws. We favor doing an advance in a draw, but we evaluate purchases first
                    //This gives us the same results as if we were evaluating advance first, but performance is better
                    //This makes us stronger than favoring buying pieces in a draw (Which probably implies our Evaluate method is incorrect?), but costs slight runtime performance
                    v = AlphaBeta(state, _maxSearchDepth - 1, (alpha == int.MinValue ? int.MinValue : alpha - 1), beta, maximizingPlayer);

                    if (v >= bestValue)
                    {
                        bestMove = move;
                    }
                }
                else
                {
                    state.PerformPurchasePiece(state.NextPieceIndex + move);
                    if (_placementMaker != null)
                    {
                        while (state.PieceToPlace != null)
                        {
                            _placementMaker.PlacePiece(state);
                        }
                    }
                    v = AlphaBeta(state, _maxSearchDepth - 1, alpha, beta, maximizingPlayer);
                    if (v > bestValue)
                    {
                        bestMove = move;
                    }
                }

                //Console.WriteLine($"Considering {m.ToString().PadLeft(2)} = {v}");


                bestValue = Math.Max(bestValue, v);
                alpha     = Math.Max(alpha, bestValue);
            }

            _thisThreadPool.Return(state);
            return(bestMove);
        }