public double Estimate(State state, int player, InterestingFacts facts)
        {
            if (state.players[player].status == PlayerStatus.Eliminated)
            {
                return(double.MinValue);
            }

            if (!killWithMinimax)
            {
                return(double.MaxValue);
            }

            if (state.isGameOver && facts.places[player] == 0)
            {
                return(double.MaxValue);
            }

            var score = 1;

            for (var i = 0; i < state.players.Length; i++)
            {
                if (i != player &&
                    state.players[i].status == PlayerStatus.Eliminated &&
                    (state.players[i].killedBy & (1 << player)) != 0)
                {
                    score += killScore;
                }
            }

            return(score);
        }
Ejemplo n.º 2
0
        public double Estimate(State state, InterestingFacts facts, int player, int pathStartLen)
        {
            var score = 0;

            if (state.players[player].status == PlayerStatus.Eliminated)
            {
                score -= 1_000_000_000;
            }
            else
            {
                for (var i = 0; i < state.players.Length; i++)
                {
                    if (state.players[i].status == PlayerStatus.Eliminated && (state.players[i].killedBy & (1 << player)) != 0)
                    {
                        score += 1_000_000;
                    }
                }
            }

            score += state.players[player].score;

            // if (state.time < Env.MAX_TICK_COUNT - 100)
            // {
            //     score += state.players[player].nitrosCollected * 20;
            //     score -= state.players[player].slowsCollected * 50;
            // }

            // score += state.players[player].nitrosCollected * 30 * (Env.TICKS_PER_REQUEST - Env.NITRO_TICKS_PER_REQUEST) / Env.TICKS_PER_REQUEST;
            // score -= state.players[player].slowsCollected * 30 * (Env.SLOW_TICKS_PER_REQUEST - Env.TICKS_PER_REQUEST) / Env.TICKS_PER_REQUEST;

            return(score);
        }
        public double Estimate(State state, InterestingFacts facts, int player, int pathStartLen)
        {
            double baseScore;

            if (state.players[player].status == PlayerStatus.Eliminated)
            {
                baseScore = -1_000_000_000;
            }
            else
            {
                baseScore = 0;
                for (var i = 0; i < state.players.Length; i++)
                {
                    if (i != player &&
                        state.players[i].status == PlayerStatus.Eliminated &&
                        (state.players[i].killedBy & (1 << player)) != 0)
                    {
                        baseScore += 10_000_000;
                    }
                }
            }

            var nitroTimeBonus  = state.players[player].nitrosCollected * 30 * (Env.TICKS_PER_REQUEST - Env.NITRO_TICKS_PER_REQUEST);
            var nitroScoreBonus = nitroTimeBonus / Env.TICKS_PER_REQUEST;

            var slowTimePenalty  = state.players[player].slowsCollected * 50 * (Env.SLOW_TICKS_PER_REQUEST - Env.TICKS_PER_REQUEST);
            var slowScorePenalty = slowTimePenalty / Env.TICKS_PER_REQUEST;

            var opponentCaptured = state.players[player].opponentTerritoryCaptured - prevCaptured;

            if (pathStartLen > 0 && opponentCaptured == 0)
            {
                return(int.MinValue);
            }

            var score = state.players[player].score - prevScore;
            var time  = state.time - prevTime;

            if (state.time < Env.MAX_TICK_COUNT - 100)
            {
                time  += slowTimePenalty - nitroTimeBonus;
                score += nitroScoreBonus - slowScorePenalty;
            }

            if (opponentCaptured > 0)
            {
                return(baseScore + 100_000.0 * opponentCaptured - 100.0 * time + score);
            }

            if (state.playersLeft == 1)
            {
                return(baseScore + score);
            }

            var totalTicks = prevLineCount * Env.TICKS_PER_REQUEST + time;

            if (limitEmptyTicks != -1 && totalTicks > limitEmptyTicks)
            {
                baseScore -= totalTicks - limitEmptyTicks;
            }

            return(baseScore + score);
        }
Ejemplo n.º 4
0
        public double Estimate(State state, InterestingFacts facts, int player, int pathStartLen)
        {
            double baseScore;

            baseScore = 0;
            for (var i = 0; i < state.players.Length; i++)
            {
                if (i != player &&
                    state.players[i].status == PlayerStatus.Eliminated &&
                    (state.players[i].killedBy & (1 << player)) != 0)
                {
                    baseScore += 1_000_000_000;
                }
            }

            var nitroTimeBonus  = state.players[player].nitrosCollected * 30 * (Env.TICKS_PER_REQUEST - Env.NITRO_TICKS_PER_REQUEST);
            var nitroScoreBonus = nitroTimeBonus / Env.TICKS_PER_REQUEST;

            var slowTimePenalty  = state.players[player].slowsCollected * 30 * (Env.SLOW_TICKS_PER_REQUEST - Env.TICKS_PER_REQUEST);
            var slowScorePenalty = slowTimePenalty / Env.TICKS_PER_REQUEST;

            var opponentCaptured = state.players[player].opponentTerritoryCaptured - prevCaptured;

            if (pathStartLen > 0 && opponentCaptured == 0)
            {
                return(int.MinValue);
            }

            var score = state.players[player].score - prevScores[player];
            var time  = state.time - prevTime;

            if (state.time < Env.MAX_TICK_COUNT - 100)
            {
                time  += slowTimePenalty - nitroTimeBonus;
                score += nitroScoreBonus - slowScorePenalty;
            }

            if (opponentCaptured > 0)
            {
#if DEBUG
                backup.Backup(state);
                for (int i = 0; i < state.players.Length; i++)
                {
                    pathsBackup[i] = facts.pathsToOwned[i].len;
                }
#endif
                while (!state.isGameOver)
                {
                    var ended = 0;
                    for (var i = 0; i < state.players.Length; i++)
                    {
                        if (state.players[i].status == PlayerStatus.Eliminated || state.players[i].status == PlayerStatus.Broken)
                        {
                            ended++;
                            continue;
                        }

                        if (state.players[i].arriveTime != 0)
                        {
                            if (facts.pathsToOwned[i].len < 0)
                            {
                                ended++;
                            }
                            continue;
                        }

                        if (facts.pathsToOwned[i].len <= 0)
                        {
                            ended++;
                        }

                        commands[i] = facts.pathsToOwned[i].ApplyNext(state, i);
                    }

                    if (ended == state.players.Length)
                    {
                        break;
                    }

                    state.NextTurn(commands, false);
                }

                var sumOpponentScore = 0;
                for (int i = 0; i < state.players.Length; i++)
                {
                    if (i == player || state.players[i].status == PlayerStatus.Eliminated || facts.places[i] > 2)
                    {
                        continue;
                    }

                    var opponentScore = state.players[i].score - prevScores[i] - facts.potentialScores[i];
                    sumOpponentScore += opponentScore;
                }
#if DEBUG
                backup.Restore(state);
                for (int i = 0; i < state.players.Length; i++)
                {
                    facts.pathsToOwned[i].len = pathsBackup[i];
                }
#endif

                return(baseScore + 10_000_000.0 + 100_000.0 * opponentCaptured - sumOpponentScore / 5.0 * 10_000.0 - 100.0 * time + score);
            }

            return(baseScore + score);
        }
        public byte GetAllowedDirectionsMask(ITimeManager timeManager, State state, int player, DistanceMap distanceMap, InterestingFacts facts)
        {
            var result = (byte)0;

            minimax.Alphabeta(timeManager, state, player, facts.pathsToOwned, distanceMap, facts);
            for (int i = 0; i < 4; i++)
            {
                if (minimax.bestResultScores[i] > 0)
                {
                    result = (byte)(result | (1 << i));
                }
            }

            return(result);
        }
Ejemplo n.º 6
0
        public void Alphabeta(ITimeManager timeManager, State state, int player, PlayerPath[] skipPaths, DistanceMap distanceMap, InterestingFacts facts)
        {
            if (skipPaths != null && (skipPlayers == null || skipPlayers.Length < state.players.Length))
            {
                skipPlayers = new bool[state.players.Length];
            }

            bestScore   = double.MinValue;
            bestDepth   = 0;
            estimations = 0;
            bestAction  = default(Direction);

            for (int i = 0; i < 4; i++)
            {
                bestResultScores[i] = double.NegativeInfinity;
            }

            var depth = 1;

            while (!timeManager.IsExpired && depth <= maxDepth)
            {
                for (int i = 0; i < 4; i++)
                {
                    resultScores[i] = double.NegativeInfinity;
                }

                if (skipPaths != null)
                {
                    for (int i = 0; i < state.players.Length; i++)
                    {
                        skipPlayers[i] = true;
                        if (i == player || state.players[i].status == PlayerStatus.Eliminated || state.players[i].status == PlayerStatus.Broken)
                        {
                            continue;
                        }

                        var active = distanceMap.nearestOpponentActive[i, player];
                        if (active != ushort.MaxValue)
                        {
                            var dist = distanceMap.distances1[i, active];
                            if (dist != -1 && dist != int.MaxValue && dist <= 2 * depth)
                            {
                                skipPlayers[i] = false;
                                continue;
                            }
                            dist = distanceMap.distances2[i, active];
                            if (dist != -1 && dist != int.MaxValue && dist <= 2 * depth)
                            {
                                skipPlayers[i] = false;
                                continue;
                            }
                        }

                        if (facts.sawCollectDistance[i] != int.MaxValue)
                        {
                            if (facts.sawCollectDistance[i] <= depth)
                            {
                                skipPlayers[i] = false;
                                continue;
                            }
                        }
                    }
                }

                var score = Alphabeta(timeManager, state, player, depth, player, double.MinValue, double.MaxValue, resultScores, out var action, 0, skipPaths, facts);
                if (double.IsNegativeInfinity(score))
                {
                    break;
                }
                bestScore  = score;
                bestAction = action;
                bestDepth  = depth;
                for (int i = 0; i < 4; i++)
                {
                    bestResultScores[i] = resultScores[i];
                }
                depth++;
            }
        }
Ejemplo n.º 7
0
        private double Alphabeta(
            ITimeManager timeManager,
            State state,
            int player,
            int depth,
            int activePlayer,
            double a,
            double b,
            double[] rootScores,
            out Direction resultAction,
            int commandsStart,
            PlayerPath[] skipPaths,
            InterestingFacts facts)
        {
            resultAction = default(Direction);
            if (timeManager.IsExpired)
            {
                return(double.NegativeInfinity);
            }

            if (state.isGameOver ||
                state.players[player].status == PlayerStatus.Eliminated ||
                depth == 0 && activePlayer == player)
            {
                estimations++;
                var score = estimator.Estimate(state, player, facts);
                return(score);
            }

            if (activePlayer == player)
            {
                depth--;
            }

            var top = state.players[activePlayer].dir == null ? 6 : 5;

            var bestRootScore = double.MinValue;

            for (byte d = 3; d <= top; d++)
            {
                var action = (Direction)(((byte)(state.players[activePlayer].dir ?? Direction.Up) + d) % 4);
                var ne     = state.players[activePlayer].arrivePos.NextCoord(action);
                if (ne == ushort.MaxValue || (state.lines[ne] & (1 << activePlayer)) != 0)
                {
                    continue;
                }

                ulong skippedMask = 0;
                commands[commandsStart + activePlayer] = action;
                var nextPlayer = activePlayer == player ? 0 : activePlayer + 1;
                for (; nextPlayer < state.players.Length; nextPlayer++)
                {
                    if (nextPlayer == player ||
                        state.players[nextPlayer].status == PlayerStatus.Eliminated ||
                        state.players[nextPlayer].status == PlayerStatus.Broken ||
                        state.players[nextPlayer].arriveTime > 0)
                    {
                        continue;
                    }

                    if (skipPaths != null && skipPlayers[nextPlayer])
                    {
                        commands[commandsStart + nextPlayer] = skipPaths[nextPlayer].ApplyNext(state, nextPlayer);
                        skippedMask += 1ul << (nextPlayer * 8);
                        continue;
                    }

                    break;
                }

                StateUndo undo = null;
                if (nextPlayer == state.players.Length)
                {
                    while (true)
                    {
                        var nextUndo = state.NextTurn(commands, withUndo: true, commandsStart: commandsStart);
                        if (undo != null)
                        {
                            nextUndo.prevUndo = undo;
                        }

                        undo           = nextUndo;
                        commandsStart += 6;

                        if (state.isGameOver || state.players[player].status == PlayerStatus.Eliminated)
                        {
                            nextPlayer = state.players.Length;
                            break;
                        }

                        if (state.players[player].arriveTime == 0)
                        {
                            nextPlayer = player;
                            break;
                        }

                        var done = false;
                        for (nextPlayer = 0; nextPlayer < state.players.Length; nextPlayer++)
                        {
                            if (nextPlayer == player ||
                                state.players[nextPlayer].status == PlayerStatus.Eliminated ||
                                state.players[nextPlayer].status == PlayerStatus.Broken ||
                                state.players[nextPlayer].arriveTime > 0)
                            {
                                continue;
                            }

                            if (skipPaths != null && skipPlayers[nextPlayer])
                            {
                                commands[commandsStart + nextPlayer] = skipPaths[nextPlayer].ApplyNext(state, nextPlayer);
                                skippedMask += 1ul << (nextPlayer * 8);
                                continue;
                            }

                            done = true;
                            break;
                        }

                        if (done)
                        {
                            break;
                        }
                    }
                }

                var score = Alphabeta(timeManager, state, player, depth, nextPlayer, a, b, null, out _, commandsStart, skipPaths, facts);

                while (undo != null)
                {
                    var prevUndo = undo.prevUndo;
                    state.Undo(undo);
                    undo           = prevUndo;
                    commandsStart -= 6;
                }

                if (skippedMask != 0)
                {
                    for (int i = 0; i < state.players.Length; i++)
                    {
                        while ((skippedMask & (0xFFul << (i * 8))) != 0)
                        {
                            skippedMask -= 1ul << (i * 8);
                            skipPaths[i].Revert();
                        }
                    }
                }

                if (double.IsNegativeInfinity(score))
                {
                    return(double.NegativeInfinity);
                }

                if (rootScores != null)
                {
                    rootScores[(int)action] = score;
                    if (score > bestRootScore)
                    {
                        bestRootScore = score;
                    }
                }
                else
                {
                    if (player == activePlayer)
                    {
                        if (score > a)
                        {
                            a            = score;
                            resultAction = action;
                        }
                    }
                    else
                    {
                        if (score < b)
                        {
                            b            = score;
                            resultAction = action;
                        }
                    }

                    if (a >= b)
                    {
                        break;
                    }
                }
            }

            return(rootScores != null ? bestRootScore
                : player == activePlayer ? a : b);
        }