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); } } }
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); }