private void PrepareTimeLimit(State state, int player, DistanceMap distanceMap) { gen++; timeLimit = Env.MAX_TICK_COUNT - state.time; for (var i = 0; i < state.players[player].lineCount; i++) { var line = state.players[player].line[i]; used[line] = gen; for (var other = 0; other < state.players.Length; other++) { if (other == player || state.players[other].status == PlayerStatus.Eliminated) { continue; } if (distanceMap.times1[other, line] != -1 && distanceMap.times1[other, line] < timeLimit) { timeLimit = distanceMap.times1[other, line]; } if (distanceMap.times2[other, line] != -1 && distanceMap.times2[other, line] < timeLimit) { timeLimit = distanceMap.times2[other, line]; } } } }
public void Start(State state, int player, DistanceMap distanceMap) { PrepareTimeLimit(state, player, distanceMap); len = 0; startLen = 0; pos = state.players[player].arrivePos; started = state.players[player].lineCount > 0; dir = state.players[player].dir; fixedNextDir = null; time = 0; shiftTime = state.players[player].shiftTime; nitroLeft = state.players[player].nitroLeft; slowLeft = state.players[player].slowLeft; }
public void BuildPath(State state, DistanceMap distanceMap, int player, ushort target) { len = 0; originalLen = 0; if (target == ushort.MaxValue) { return; } if (distanceMap.times2[player, target] < distanceMap.times1[player, target]) { var start = state.players[player].arrivePos; int cur = target; while (true) { var next = distanceMap.paths2[player, cur]; if (next == -1) { break; } dirs[len++] = ((ushort)next).DirTo((ushort)cur); originalLen++; cur = next; } while (cur != start) { var next = distanceMap.paths1[player, cur]; dirs[len++] = ((ushort)next).DirTo((ushort)cur); originalLen++; cur = next; } } else { var start = state.players[player].arrivePos; for (int cur = target; cur != start;) { var next = distanceMap.paths1[player, cur]; dirs[len++] = ((ushort)next).DirTo((ushort)cur); originalLen++; cur = next; } } }
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 void Build(State state, DistanceMap distanceMap) { for (int i = 0; i < state.players.Length; i++) { places[i] = i; potentialScores[i] = 0; } for (int i = 0; i < state.players.Length - 1; i++) { for (int k = i + 1; k < state.players.Length; k++) { if (state.players[places[i]].score < state.players[places[k]].score) { var tmp = places[i]; places[i] = places[k]; places[k] = tmp; } } } for (int i = 0; i < state.players.Length; i++) { if (state.players[i].status == PlayerStatus.Eliminated || state.players[i].status == PlayerStatus.Broken) { continue; } sawCollectTime[i] = int.MaxValue; sawCollectDistance[i] = int.MaxValue; distCount[i] = 0; pathsToOwned[i].BuildPath(state, distanceMap, i, distanceMap.nearestOwned[i]); } for (ushort c = 0; c < Env.CELLS_COUNT; ++c) { territoryTtl[c] = int.MaxValue; } for (int b = 0; b < state.bonusCount; b++) { if (state.bonuses[b].type == BonusType.Saw) { for (var i = 0; i < state.players.Length; i++) { if (state.players[i].status == PlayerStatus.Eliminated || state.players[i].status == PlayerStatus.Broken) { continue; } var st = distanceMap.times1[i, state.bonuses[b].pos]; if (st != -1 && st != int.MaxValue && st < sawCollectTime[i]) { sawCollectTime[i] = st; } var sd = distanceMap.distances1[i, state.bonuses[b].pos]; if (sd != -1 && sd != int.MaxValue && sd < sawCollectDistance[i]) { sawCollectDistance[i] = sd; } st = distanceMap.times2[i, state.bonuses[b].pos]; if (st != -1 && st != int.MaxValue && st < sawCollectTime[i]) { sawCollectTime[i] = st; } sd = distanceMap.distances2[i, state.bonuses[b].pos]; if (sd != -1 && sd != int.MaxValue && sd < sawCollectDistance[i]) { sawCollectDistance[i] = sd; } } } } var territoryVersion = state.territoryVersion; backup.Backup(state); 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 (pathsToOwned[i].len < 0) { ended++; } continue; } if (pathsToOwned[i].len <= 0) { ended++; } commands[i] = pathsToOwned[i].ApplyNext(state, i); distCount[i]++; } if (ended == state.players.Length) { for (int i = 0; i < state.players.Length; i++) { potentialScores[i] = state.players[i].score - backup.players[i].score; } break; } state.NextTurn(commands, false); if (state.territoryVersion != territoryVersion) { territoryVersion = state.territoryVersion; for (ushort c = 0; c < Env.CELLS_COUNT; ++c) { if (territoryTtl[c] == int.MaxValue && state.territory[c] != backup.territory[c]) { territoryTtl[c] = state.time - backup.time; } } } for (var i = 0; i < state.players.Length; i++) { if (state.players[i].status == PlayerStatus.Eliminated || state.players[i].status == PlayerStatus.Broken) { continue; } if (state.players[i].sawsCollected > 0) { if (state.time - backup.time < sawCollectTime[i]) { sawCollectTime[i] = state.time - backup.time; } if (distCount[i] < sawCollectDistance[i]) { sawCollectDistance[i] = distCount[i]; } } } } backup.Restore(state); for (var i = 0; i < state.players.Length; i++) { pathsToOwned[i].Reset(); } }
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); }