예제 #1
0
        public StateUndo NextTurn(Direction[] commands, bool withUndo, int commandsStart = 0)
        {
            StateUndo undo = null;

            if (withUndo)
            {
                undo = undos.Get();
                undo.Before(this);
            }

            ApplyCommands(commands, commandsStart);

            var timeDelta = RenewArriveTime();

            time += timeDelta;
            if (time > Env.MAX_TICK_COUNT)
            {
                isGameOver = true;
                if (withUndo)
                {
                    undo.After(this);
                }

                return(undo);
            }

            Move(timeDelta);

            CheckIntermediateCollisions();

            Capture();

            CheckLoss();

            CheckIsAte();

            CaptureBonuses(undo);

            capture.ApplyTo(this, undo);

            MoveDone();

            Done();

            if (withUndo)
            {
                undo.After(this);
            }
            return(undo);
        }
예제 #2
0
        public void ApplyTo(State state, StateUndo undo)
        {
            for (var player = 0; player < territoryCaptureCount.Length; player++)
            {
                if (state.players[player].status == PlayerStatus.Loser)
                {
                    for (var i = 0; i < territoryCaptureCount[player]; i++)
                    {
                        var v    = territoryCapture[player, i];
                        var mask = territoryCaptureMask[v];
                        territoryCaptureMask[v] = mask & ~(1 << player);
                    }
                }
            }

            for (var player = 0; player < territoryCaptureCount.Length; player++)
            {
                if (state.players[player].status == PlayerStatus.Eliminated)
                {
                    continue;
                }

                for (var i = 0; i < territoryCaptureCount[player]; i++)
                {
                    var v    = territoryCapture[player, i];
                    var mask = territoryCaptureMask[v] & 0xFF;
                    if ((mask & ~(1 << player)) == 0)
                    {
                        var owner = state.territory[v];
                        if (owner != player)
                        {
                            if (owner != 0xFF && state.players[owner].status != PlayerStatus.Eliminated)
                            {
                                state.players[player].tickScore += Env.ENEMY_TERRITORY_SCORE - Env.NEUTRAL_TERRITORY_SCORE;
                                state.players[player].opponentTerritoryCaptured++;
                                state.players[owner].territory--;
                            }

                            state.players[player].territory++;
                            undo?.NotifyCapture(state);

                            state.territory[v] = (byte)player;
                            state.territoryVersion++;
                        }
                    }
                }
            }
        }
예제 #3
0
        private void CaptureBonuses(StateUndo undo)
        {
            for (var i = 0; i < players.Length; i++)
            {
                if (players[i].status == PlayerStatus.Eliminated || players[i].status == PlayerStatus.Broken)
                {
                    continue;
                }

                if (players[i].arriveTime == 0 && players[i].arrivePos != ushort.MaxValue)
                {
                    players[i].TickAction();

                    for (var b = 0; b < bonusCount;)
                    {
                        if (bonuses[b].pos != players[i].arrivePos && !capture.BelongsTo(bonuses[b].pos, i))
                        {
                            b++;
                        }
                        else
                        {
                            if (bonuses[b].type == BonusType.N)
                            {
                                var bonusTime = bonuses[b].ActiveTicks(i);
                                if (players[i].nitroLeft > 0)
                                {
                                    players[i].nitroLeft += bonusTime;
                                }
                                else
                                {
                                    players[i].nitroLeft = bonusTime;
                                }
                                players[i].UpdateShiftTime();
                                players[i].nitrosCollected++;
                            }
                            else if (bonuses[b].type == BonusType.S)
                            {
                                var bonusTime = bonuses[b].ActiveTicks(i);
                                if (players[i].slowLeft > 0)
                                {
                                    players[i].slowLeft += bonusTime;
                                }
                                else
                                {
                                    players[i].slowLeft = bonusTime;
                                }
                                players[i].UpdateShiftTime();
                                players[i].slowsCollected++;
                            }
                            else if (bonuses[b].type == BonusType.Saw)
                            {
                                players[i].sawsCollected++;
                                var sawStatus = 0ul;
                                var v         = players[i].arrivePos;
                                while (true)
                                {
                                    v = v.NextCoord(players[i].dir.Value);
                                    if (v == ushort.MaxValue)
                                    {
                                        break;
                                    }
                                    for (var k = 0; k < players.Length; k++)
                                    {
                                        if (k == i || players[k].status == PlayerStatus.Eliminated)
                                        {
                                            continue;
                                        }
                                        if (players[k].arrivePos == v || players[k].pos == v && players[k].arriveTime > 0)
                                        {
                                            sawStatus            |= 0xFFul << (k * 8);
                                            players[k].status     = PlayerStatus.Loser;
                                            players[k].killedBy   = (byte)(players[k].killedBy | (1 << i));
                                            players[i].tickScore += Env.SAW_KILL_SCORE;
                                        }
                                    }

                                    var owner = territory[v];
                                    if (owner != 0xFF && owner != i)
                                    {
                                        if (players[owner].status != PlayerStatus.Eliminated)
                                        {
                                            sawStatus |= 1ul << (owner * 8);
                                        }
                                    }
                                }

                                for (var k = 0; k < players.Length; k++)
                                {
                                    if (k == i || players[k].status == PlayerStatus.Eliminated)
                                    {
                                        continue;
                                    }

                                    if (((sawStatus >> (k * 8)) & 0xFF) != 1)
                                    {
                                        continue;
                                    }

                                    players[i].tickScore += Env.SAW_SCORE;
                                    var vx = players[i].arrivePos % Env.X_CELLS_COUNT;
                                    var vy = players[i].arrivePos / Env.X_CELLS_COUNT;
                                    if (players[i].dir.Value == Direction.Up || players[i].dir.Value == Direction.Down)
                                    {
                                        if (players[k].arrivePos % Env.X_CELLS_COUNT < vx)
                                        {
                                            var pos = 0;
                                            for (var y = 0; y < Env.Y_CELLS_COUNT; y++)
                                            {
                                                pos += vx;
                                                for (var x = vx; x < Env.X_CELLS_COUNT; x++, pos++)
                                                {
                                                    if (territory[pos] == k)
                                                    {
                                                        players[k].territory--;
                                                        undo?.NotifyCapture(this);
                                                        territory[pos] = 0xFF;
                                                        territoryVersion++;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            var pos = 0;
                                            for (var y = 0; y < Env.Y_CELLS_COUNT; y++)
                                            {
                                                for (var x = 0; x <= vx; x++, pos++)
                                                {
                                                    if (territory[pos] == k)
                                                    {
                                                        players[k].territory--;
                                                        undo?.NotifyCapture(this);
                                                        territory[pos] = 0xFF;
                                                        territoryVersion++;
                                                    }
                                                }

                                                pos += Env.X_CELLS_COUNT - vx - 1;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        if (players[k].arrivePos / Env.X_CELLS_COUNT < vy)
                                        {
                                            var pos = vy * Env.X_CELLS_COUNT;
                                            for (var y = vy; y < Env.Y_CELLS_COUNT; y++)
                                            {
                                                for (var x = 0; x < Env.X_CELLS_COUNT; x++, pos++)
                                                {
                                                    if (territory[pos] == k)
                                                    {
                                                        players[k].territory--;
                                                        undo?.NotifyCapture(this);
                                                        territory[pos] = 0xFF;
                                                        territoryVersion++;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            var pos = 0;
                                            for (var y = 0; y <= vy; y++)
                                            {
                                                for (var x = 0; x < Env.X_CELLS_COUNT; x++, pos++)
                                                {
                                                    if (territory[pos] == k)
                                                    {
                                                        players[k].territory--;
                                                        undo?.NotifyCapture(this);
                                                        territory[pos] = 0xFF;
                                                        territoryVersion++;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if (b != bonusCount - 1)
                            {
                                var tmp = bonuses[b];
                                bonuses[b] = bonuses[bonusCount - 1];
                                bonuses[bonusCount - 1] = tmp;
                            }

                            bonusCount--;
                        }
                    }
                }
            }
        }
예제 #4
0
 public void Undo(StateUndo undo)
 {
     undo.Undo(this);
     undos.Return(undo);
 }
예제 #5
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);
        }