Пример #1
0
        public bool Generate(State state, int player, DistanceMap distanceMap, InterestingFacts facts, ReliablePathBuilder pathBuilder, byte allowedDirectionsMask = 0xFF)
        {
            pathBuilder.Start(state, player, distanceMap);
            while (true)
            {
                if (pathBuilder.dir == null)
                {
                    dirs[0]       = Direction.Up;
                    dirs[1]       = Direction.Left;
                    dirs[2]       = Direction.Right;
                    dirs[3]       = Direction.Down;
                    dirChances[0] = 1;
                    dirChances[1] = 1;
                    dirChances[2] = 1;
                    dirChances[3] = 1;
                    dirsCount     = 4;
                    random.Shuffle(dirs);
                }
                else
                {
                    dirs[0]   = pathBuilder.dir.Value;
                    dirs[1]   = (Direction)(((int)dirs[0] + 1) % 4);
                    dirs[2]   = (Direction)(((int)dirs[0] + 3) % 4);
                    dirsCount = 3;

                    if (random.Next(2) == 0)
                    {
                        var tmp = dirs[1];
                        dirs[1] = dirs[2];
                        dirs[2] = tmp;
                    }

                    if (random.Next(sameDirChance) == 0)
                    {
                        var other = random.Next(1, 3);
                        var tmp   = dirs[0];
                        dirs[0]     = dirs[other];
                        dirs[other] = tmp;
                    }
                }

                var found = false;
                for (var i = 0; i < dirsCount; i++)
                {
                    var nextDir = dirs[i];
                    if (pathBuilder.len == 0 && (allowedDirectionsMask & (1 << (int)nextDir)) == 0)
                    {
                        continue;
                    }

                    var nextPos = pathBuilder.pos.NextCoord(nextDir);
                    if (nextPos == ushort.MaxValue)
                    {
                        continue;
                    }

                    if (!pathBuilder.TryAdd(state, player, distanceMap, facts, nextPos))
                    {
                        continue;
                    }

                    found = true;
                    break;
                }

                if (!found)
                {
                    return(false);
                }

                if (pathBuilder.started &&
                    state.territory[pathBuilder.pos] == player &&
                    (!pathBuilder.useTerritoryTtl || facts.territoryTtl[pathBuilder.pos] > pathBuilder.time))
                {
                    return(true);
                }
            }
        }
Пример #2
0
        public bool TryAdd(State state, int player, DistanceMap distanceMap, InterestingFacts facts, ushort nextPos)
        {
            if (used[nextPos] == gen)
            {
                return(false);
            }

            var nextDir = pos.DirTo(nextPos);

            if (fixedNextDir != null && fixedNextDir.Value != nextDir)
            {
                return(false);
            }

            var nextTime = time + shiftTime;

            if (nextTime > timeLimit || nextTime == timeLimit && (!started || state.territory[nextPos] != player || useTerritoryTtl && facts.territoryTtl[nextPos] <= nextTime))
            {
                return(false);
            }

            var nextNitroLeft = nitroLeft;
            var nextSlowLeft  = slowLeft;

            if (nextNitroLeft > 0)
            {
                nextNitroLeft--;
            }
            if (nextSlowLeft > 0)
            {
                nextSlowLeft--;
            }
            for (var b = 0; b < state.bonusCount; b++)
            {
                if (state.bonuses[b].pos == nextPos)
                {
                    if (state.bonuses[b].type == BonusType.S)
                    {
                        nextSlowLeft += state.bonuses[b].ActiveTicks(player);
                    }
                    else if (state.bonuses[b].type == BonusType.N)
                    {
                        nextNitroLeft += state.bonuses[b].ActiveTicks(player);
                    }
                }
            }

            var nextShiftTime = Player.GetShiftTime(nextNitroLeft, nextSlowLeft);
            var escapeTime    = nextTime + nextShiftTime;

            var nextTimeLimit = timeLimit;
            var nextStarted   = started || state.territory[nextPos] != player ||
                                useTerritoryTtl && facts.territoryTtl[nextPos] <= nextTime;
            Direction?nextFixedNextDir = null;

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

                    var otherTimeToPos = distanceMap.times1[other, nextPos];
                    if (otherTimeToPos != -1 && otherTimeToPos != int.MaxValue)
                    {
                        if (otherTimeToPos < nextTimeLimit)
                        {
                            nextTimeLimit = otherTimeToPos;
                        }

                        if (state.players[other].arrivePos == nextPos)
                        {
                            nextTimeLimit = -1;
                            break;
                        }

                        var finished        = state.territory[nextPos] == player && (!useTerritoryTtl || facts.territoryTtl[nextPos] > nextTime);
                        var enterLineLen    = len - startLen + state.players[player].lineCount;
                        var lineLen         = finished ? 0 : enterLineLen + 1;
                        var canKillOnEnter  = distanceMap.enterLineLens1[other, nextPos] <= enterLineLen;
                        var canKillOnEscape = distanceMap.lineLens1[other, nextPos] <= lineLen;
                        var canKillInside   = distanceMap.enterLineLens1[other, nextPos] <= lineLen;

                        if (otherTimeToPos < escapeTime && canKillOnEscape)
                        {
                            nextTimeLimit = -1;
                            break;
                        }

                        var otherEnterTime = distanceMap.enterTimes1[other, nextPos];
                        if (otherEnterTime != -1 && otherEnterTime != int.MaxValue)
                        {
                            if (otherEnterTime < nextTime && canKillOnEnter)
                            {
                                nextTimeLimit = -1;
                                break;
                            }

                            if (otherEnterTime == nextTime && canKillInside)
                            {
                                nextTimeLimit = -1;
                                break;
                            }

                            if (otherEnterTime < escapeTime && canKillInside)
                            {
                                var enterCommands = distanceMap.enterCommands1[other, nextPos];
                                if ((enterCommands & (enterCommands - 1)) != 0)
                                {
                                    nextTimeLimit = -1;
                                    break;
                                }

                                for (int d = 0; d < 4; d++)
                                {
                                    if (1 << d == enterCommands)
                                    {
                                        nextFixedNextDir = (Direction)d;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    otherTimeToPos = distanceMap.times2[other, nextPos];
                    if (otherTimeToPos != -1 && otherTimeToPos != int.MaxValue)
                    {
                        if (otherTimeToPos < nextTimeLimit)
                        {
                            nextTimeLimit = otherTimeToPos;
                        }

                        if (state.players[other].arrivePos == nextPos)
                        {
                            nextTimeLimit = -1;
                            break;
                        }

                        var finished        = state.territory[nextPos] == player && (!useTerritoryTtl || facts.territoryTtl[nextPos] > nextTime);
                        var enterLineLen    = len - startLen + state.players[player].lineCount;
                        var lineLen         = finished ? 0 : enterLineLen + 1;
                        var canKillOnEnter  = distanceMap.enterLineLens2[other, nextPos] <= enterLineLen;
                        var canKillOnEscape = distanceMap.lineLens2[other, nextPos] <= lineLen;
                        var canKillInside   = distanceMap.enterLineLens2[other, nextPos] <= lineLen;

                        if (otherTimeToPos < escapeTime && canKillOnEscape)
                        {
                            nextTimeLimit = -1;
                            break;
                        }

                        var otherEnterTime = distanceMap.enterTimes2[other, nextPos];
                        if (otherEnterTime != -1 && otherEnterTime != int.MaxValue)
                        {
                            if (otherEnterTime < nextTime && canKillOnEnter)
                            {
                                nextTimeLimit = -1;
                                break;
                            }

                            if (otherEnterTime == nextTime && canKillInside)
                            {
                                nextTimeLimit = -1;
                                break;
                            }

                            if (otherEnterTime < escapeTime && canKillInside)
                            {
                                var enterCommands = distanceMap.enterCommands2[other, nextPos];
                                if ((enterCommands & (enterCommands - 1)) != 0)
                                {
                                    nextTimeLimit = -1;
                                    break;
                                }

                                for (int d = 0; d < 4; d++)
                                {
                                    if (1 << d == enterCommands)
                                    {
                                        nextFixedNextDir = (Direction)d;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (nextTime > nextTimeLimit ||
                nextTime == nextTimeLimit && (!started || state.territory[nextPos] != player || useTerritoryTtl && facts.territoryTtl[nextPos] <= nextTime))
            {
                return(false);
            }

            coords[len]   = nextPos;
            times[len]    = nextTime;
            used[nextPos] = gen;
            if (!started && nextStarted)
            {
                startLen = len;
            }

            len++;
            fixedNextDir = nextFixedNextDir;
            dir          = nextDir;
            pos          = nextPos;
            time         = nextTime;
            timeLimit    = nextTimeLimit;
            nitroLeft    = nextNitroLeft;
            slowLeft     = nextSlowLeft;
            shiftTime    = nextShiftTime;
            started      = nextStarted;
            return(true);
        }