심플 레이스 KoTH
이 도전은 공식적으로 끝났습니다. 추가 제출은 경쟁력이 없습니다 (하지만 여전히 환영합니다!). 여기 에서 점수보기
이 챌린지에서 제출물 ( "봇")은 가능한 한 많은 레이스에서 우승하려는 자바 스크립트 함수 여야합니다. 각 레이스에서 봇은 100 유닛의 거리를 가능한 한 빨리 이동하는 데 사용해야하는 제한된 양의 에너지를 갖게됩니다.
역학
각 게임은 여러 차례의 턴으로 구성된 여러 종족으로 구성됩니다. 매 차례마다 봇은 앞으로 이동할 음이 아닌 거리를 선택합니다. 소비 된 에너지의 양은 이동 한 거리의 제곱과 같습니다 (봇은 더 먼 거리를 반환 할 경우 에너지 수준이 허용하는 한 멀리 만 이동합니다).
각 레이스가 시작될 때 봇의 위치는 0으로 재설정됩니다. 하나 이상의 봇이 100 유닛 거리에 도달하면 레이스가 종료됩니다. 봇이 처음부터 100 유닛 이상 떨어진 거리를 반환하면 이기기 위해 필요한만큼만 이동합니다. 모든 레이스가 시작될 때 봇은 마지막 레이스에서 남은 에너지 외에 100 에너지를받습니다. 그들은 또한 이전 레이스에서 여행 한 모든 유닛에 대해 1 에너지의 보너스를받습니다.
포인트들
각 레이스가 끝날 때 모든 봇은 게임이 종료 될 때 이동 한 유닛 10 개당 1 포인트를받습니다 (포인트의 일부 포함). 게임이 끝나면 가장 많은 점수를 얻은 봇이 승리합니다.
봇이 특정 수의 레이스에 최적화 될 가능성이 높기 때문에 모든 봇이 경쟁하는 5 가지 범주가 있습니다 : 250 개 레이스, 750 개 레이스, 2500 개 레이스, 7500 개 레이스, 25000 개 레이스. 봇의 전체 점수는 각 카테고리의 레이스 당 평균 점수의 합계이며 가능한 최고 점수는 50 점입니다.
입출력
봇은 다음과 같은 인수를받습니다 : dist(현재 레이스에서 이동 한 거리), energy(보유한 에너지의 양), bots(마지막 턴이 끝날 때까지 다른 모든 봇의 거리 배열, 각 종족의 끝) 및 storage, 기본적으로 빈 개체이며 종족 간의 정보를 저장하는 데 사용할 수 있습니다.
예제 봇
팔로어는 턴당 평균 이동량만큼 평균 봇보다 앞서도록 노력할 것입니다.
{
"Follower": function(dist, energy, bots, storage) {
storage.turns = storage.turns || 0;
if (Math.max(...bots))
storage.avg = ((storage.avg || 0) * storage.turns++ + bots.reduce((a, b, i) => a + (b - storage.last[i]), 0) / bots.length) / storage.turns;
storage.last = bots;
return (bots.reduce((a, b) => a + b, 0) / bots.length + (storage.avg || 1)) - dist;
}
}
제어 장치
// Each bot should be placed in this object
var bot_data = {
"Follower": function(dist, energy, bots, storage) {
storage.turns = storage.turns || 0;
if (Math.max(...bots))
storage.avg = ((storage.avg || 0) * storage.turns++ + bots.reduce((a, b, i) => a + (b - storage.last[i]), 0) / bots.length) / storage.turns;
storage.last = bots;
return (bots.reduce((a, b) => a + b, 0) / bots.length + (storage.avg || 1)) - dist;
}
};
var games = 0;
var records = {};
// races: Number of races
// log: Array of bot names to log information about, or null for no logging
// Per-turn logging will only happen in games with less than 10 races
// Per-race logging will only happen in games with less than 100 races
// bold: Whether to use bold text when logging information
var run_game = function(races, log = [], bold = true) {
var perf_now = performance.now();
var bots = [];
games++;
for (let bot in bot_data)
bots.push({
name: bot,
run: bot_data[bot]
});
var uids = new Array(bots.length);
for (let i = 0; i < uids.length; i++)
uids[i] = i;
var race = 0;
var turn = 0;
for (let r = 0; r < races; r++) {
race++;
for (let j, i = 0; i < uids.length; i++) {
j = Math.random() * (i + 1) | 0;
[uids[i], uids[j]][uids[j], uids[i]];
}
for (let b, i = 0; i < bots.length; i++) {
b = bots[i];
bots[i] = {
name: b.name,
run: b.run,
uid: uids[i],
dist: 0,
energy: (b.energy || 0) + 100,
points: b.points || 0,
storage: b.storage || {},
next: 0,
inactive: 0
};
}
turn = 0;
while ((bots.every(b => b.dist < 100) && bots.some(b => b.energy > 0 && b.inactive < 3))) {
turn++;
for (let b, i = 0; i < bots.length; i++) {
b = bots[i];
try {
b.next = b.run(
b.dist, b.energy,
bots.filter(o => o.uid != b.uid).map(o => o.dist),
b.storage
);
if (log && log.includes(b.name) && races < 10)
console.log("[" + race + ":" + turn + "] " + b.name + "(" + (Math.round(b.dist * 1000) / 1000) + "," + (Math.round(b.energy * 1000) / 1000) + "):", b.next);
} catch(e) {
if (log && races < 10)
console.warn("[" + race + ":" + turn + "] " + b.name + ":\n" + (e.stack || e.message));
b.next = 0;
}
b.next = Number(b.next);
if (Number.isNaN(b.next))
b.next = 0;
b.next = Math.max(Math.min(b.next, 100 - b.dist, Math.sqrt(b.energy)), 0);
if (!b.next)
b.inactive++;
}
for (let b, i = 0; i < bots.length; i++) {
b = bots[i];
b.dist += b.next;
b.energy = Math.max(b.energy - b.next ** 2, 0);
}
}
for (let b, i = 0; i < bots.length; i++) {
b = bots[i];
b.energy = b.energy + b.dist;
b.points += b.dist / 10;
}
if (log && races < 100)
console.log(
(bold ? "%c" : "") + "Race " + race + ":\n" +
(bold ? "%c" : "") + bots.map(b => b).sort((a, b) => b.dist - a.dist).map(
b => b.name.slice(0, 16) + " ".repeat(20 - Math.min(b.name.length, 16)) + (Math.round(b.dist * 1000) / 10000)
).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
);
}
for (let i = 0; i < bots.length; i++)
records[bots[i].name] = (records[bots[i].name] || 0) + bots[i].points / races;
if (log)
console.log(
(bold ? "%c" : "") + "Average Points/Race (" + races + " races, " + (Math.ceil((performance.now() - perf_now) * 1000) / 1000) + "ms):\n" +
(bold ? "%c" : "") + bots.sort((a, b) => b.points - a.points).map(
b => b.name.slice(0, 16) + " ".repeat(20 - Math.min(b.name.length, 16)) + (Math.round((b.points / races) * 10000) / 10000)
).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
);
};
// Print and clear records for average scores
var print_records = function(bold = true) {
console.log(
(bold ? "%c" : "") + "Sum of Average Points/Game:\n" +
(bold ? "%c" : "") + Object.entries(records).sort((a, b) => b[1] - a[1]).map(
b => b[0].slice(0, 16) + " ".repeat(20 - Math.min(b[0].length, 16)) + (Math.round(b[1] * 10000) / 10000)
).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
);
};
var clear_records = function() {
records = {};
};
// Default race categories
run_game(250);
run_game(750);
run_game(2500);
run_game(7500);
run_game(25000);
print_records();
규칙
3 턴 연속 이동 한 봇이 없으면 레이스가 종료됩니다 (점수는 계속 계산됩니다).
봇에 오류가 발생하면 턴을 잃게됩니다 (즉, 이동하지 않음).
봇은 컨트롤러 또는 다른 봇을 조작하거나 기타 악의적 일 수 없습니다.
봇은 적절한 시간 내에 실행되어야합니다.
봇은 결정적이어야합니다. 봇의 인수에 의해 시드되지 않는 한 임의성이 없음
잡담: https://chat.stackexchange.com/rooms/112222/simple-race-koth
봇 마감일 : 9 월 4 일 금요일 12:00 UTC (08:00 EDT)
답변
보정기
"SubOptimal"에서 파생 된 Compensator는 "Horde / Burst"전략을 명시 적으로 제공하지 않으며, 오히려 처음이 아니었다면 이전 턴에 모든 에너지를 사용하지 않았을 수 있다는 지식을 통해 자연스럽게 보상합니다. 예상보다 더 많은 에너지를 가질 수 있습니다. 이 과도한 에너지 공급을 활용하기 위해이 봇은 초과 에너지의 절반을 사용하여 더 빠른 레이스를 시도하고 강제하지만 나머지 절반은 예비 에너지를 유지하여 여러 레이스에 걸쳐 잉여 에너지의 효과를 확장합니다.
형제 (SubOptimal)보다 약간 더 나은 성능을 보이는 것으로 보이며,이 제출 시점에 다른 모든 봇보다 약간 앞서 있습니다.
{
"Compensator": function(dist, energy, bots, storage) {
if ( dist == 0)
{
if (storage.targetStartingEnergy == undefined)
{
storage.targetStartingEnergy = energy;
storage.nominalStartingEnergy = energy + 100;
}
else
{
if (energy <= storage.nominalStartingEnergy)
{
storage.targetStartingEnergy = energy;
}
else
{
storage.targetStartingEnergy = ((energy - storage.nominalStartingEnergy) * 0.5) + storage.nominalStartingEnergy;
}
}
if (storage.raceNumber == undefined)
{
storage.raceNumber = 1;
}
else
{
storage.raceNumber++;
}
storage.energyConsumptionRate = storage.targetStartingEnergy / 100;
}
let step = 0;
if (storage.raceNumber == 1)
{
step = 1;
}
else
{
step = storage.energyConsumptionRate;
}
return step;
}
}
속도 제어
{
"Rate control": function(distanceTravelled, energyLeft, _, s) {
if (distanceTravelled === 0) {
for (let i = 100; i > 0; --i) {
if (10000 / i > energyLeft) {
s.travelSpeed = 100 / (i + 1);
break;
}
}
}
return s.travelSpeed;
}
}
각 라운드는 결승선에 도달하기 위해 모든 에너지를 사용합니다. 이 항목은 턴당 1 개 이상의 에너지 만 사용하는 동시에 항상 끝까지 도달하도록하기 때문에 "느리고 꾸준함"보다 훨씬 좋습니다. 최적화되지 않았지만 여전히 상당히 빠릅니다.
천천히 그리고 착실히
{
"Slow and steady": function() {
return 1;
}
}
이 챌린지로 무엇을해야하는지 알아내는 동안베이스 라인 봇. 전혀 적응하지 않으므로 일종의 메타가 발생하면 지속적으로 잃을 수 있습니다.
미리 계산 된
{
"precomputed": function(dist, energy, bots, storage) {
if (dist === 0) {
let movements = Array.from(new Array(100), _=>1)
const totalEnergyConsumed = () => movements.reduce((a,c)=>a+c**2,0)
let currentIndex = 0
while(totalEnergyConsumed() < energy) {
movements[currentIndex] += movements[currentIndex + 1]
movements.splice(currentIndex + 1, 1)
if (++currentIndex >= movements.length - 1) {
currentIndex = 0
}
}
currentIndex = movements.length
while(totalEnergyConsumed() > energy) {
if(movements[currentIndex] > 1) {
movements[currentIndex]--
movements.push(1)
} else {
currentIndex--
}
}
storage.movements = {}
movements.reduce((a,c)=>{storage.movements[a]=c;return a+c}, 0)
}
return storage.movements[dist]
}
}
사용 가능한 모든 에너지를 사용하면서 전체 레이스에서 거의 동일한 속도로 이동하기 위해 끝까지의 전체 경로를 계산하여 레이스를 시작합니다.
구십
{
"Ninety": function(dist, energy, bots, storage) {
if (dist === 0) {
for (let i = 90; i > 0; --i) {
if (8100 / i > (energy - 10)) {
storage.travelSpeed = 90 / (i + 1);
break;
}
}
}
if (dist >= 89) {
return 1;
}
return storage.travelSpeed;
}
}
라운드 당 9 점을 목표로합니다. 얼마나 잘하는지는 잘 모르겠지만 봇이 그것보다 더 빨리 끝낼 때 점수를 잃을 가능성이 적습니다 (이것이 분기 된 Rate Control과 비교할 때).
펄스
"Pulse": function(dist, energy, bots, storage) {
storage.round = storage.round ? storage.round+1 : 1;
if(storage.round%500==0) return Math.max([...bots])+50
return Math.floor(Math.sqrt(energy/100))
}
각 단계는 에너지의 1 % 만 사용합니다. 500 턴마다이 순간 1 위의 거리를 차지하고 50 번 더 패스합니다.
잭 인 더 박스
40 번의 동작으로 게임을 이길 때까지 에너지를 절약하여 게임당 평균 동작 수를 줄입니다.
{
"Jack in the Box": function(dist, energy, bots, storage) {
if (!dist) {
if (energy >= 250) {
storage.speed = energy / 100
} else {
storage.speed = .5
}
}
return storage.speed
}
}
바보
Simpleton은 단지 이기고 싶어합니다 :(
{
"Simpleton": function(dist, energy, bots, storage) {
return energy / (100 - dist)
}
}
확고한
Steady는 매 턴마다 같은 양을하려고하지만 여분의 에너지가있는 것을 좋아하지 않습니다.
{
"Steady": function(dist, energy, bots, storage) {
storage.turns = storage.turns || 0
storage.totalTurns = storage.totalTurns || 0
storage.games = storage.games || 0
storage.totalEnergyGained = storage.totalEnergyGained || 0
storage.previousEnergy = storage.previousEnergy || 0
if (!dist) {
if (storage.games == 0) {
storage.speed = 1
} else {
storage.totalTurns += storage.turns
storage.turns = 0
storage.speed = Math.sqrt(storage.totalEnergyGained / storage.totalTurns) + storage.previousEnergy / storage.totalTurns
}
storage.totalEnergyGained += energy - storage.previousEnergy
storage.games++
}
storage.turns++;
storage.previousEnergy = Math.max(energy - Math.max(Math.min(storage.speed, 100 - dist, Math.sqrt(energy)), 0) ** 2, 0)
return storage.speed;
}
}
차선
다른 레이서에게 영향을 미칠 수있는 방법이없는 최적의 솔루션은 모든 에너지를 사용하여 다음 라운드에서 가장 많은 에너지를 얻고 상대방의 에너지를 거부하기 위해 먼저 완료하도록하는 것입니다. 이를 위해 첫 번째 레이스에서 턴당 1.0 에너지를 소비 한 다음 후속 레이스에서 턴당 2.0 에너지를 소비하면됩니다 (100 거리에서 승리 할 때 추가로 100 에너지가 주어짐).
이는 봇의 에너지 / 레이스 시작시 이동 거리를 계산하고이 값을 저장 한 다음 레이스의 매 턴마다이 값을 반환함으로써 달성 할 수 있습니다.
이제 우리는 상대 효과에 대한 최적의 솔루션을 알고 있으므로 상대가 수행 할 수 있고 다른 사람에게 영향을 줄 수있는 행동을 고려해야합니다. 이 게임에서 유일한 실제 효과는 승자가되어 현재 레이스를 강제 종료 할 수있는 능력입니다. 봇은 에너지를 축적하고 축적 할 수 있기 때문에 에너지 소비를 최소화하고 에너지 생산을 극대화하여 특정 종족에서 많은 점수를 얻을 수있는 기회를 희생하고 대신 한 종족에서 누적 된 점수를 소비하여 다른 봇을 지배하고 승리 할 수 있습니다. 경주. 이 전략은 전반적으로 높은 점수를 얻지는 못하지만 레이스가 100 턴 후에 끝날 것으로 예상하는 봇에게 영향을 미칩니다. 따라서 레이스의 평균 턴 수가 줄어 듭니다. 따라서이 효과를 보완하기 위해이 "허드 버스트"전략을 사용하는 봇의 효과를 에뮬레이트하는 요소를 추가하여 최적 솔루션에서 차선책을 도출합니다.
이 요소는 봇이 다른 모든 봇 전략을 통합 한 다음 분석을 수행하여 요소를 결정하지 않는 한 계산할 수 없습니다. 이것은 실제로 KoTH 도전 정신이 아니며 허용되지 않을 수 있습니다. 따라서이 봇에 대해 간단한 경험적 분석을 수행하여 제출 시점의 요인을 결정하고 이후의 봇이 더 간섭 할 수 있다는 가정하에 제출이 많을수록 요인을 증가시킬 제출 수를 기반으로 스칼라를 추가했습니다.
궁극적으로 공식은 다음과 같습니다.
distance_per_turn = 시작 _ 에너지 / ((race_distance + hoard_burst_factor) * (1.0 + (number_of_bots-number_of_bots_at_submission) * 0.1))
{
"Suboptimal": function(dist, energy, bots, storage) {
if ( dist == 0)
{
storage.energyConsumptionRate = energy / ((100 + 10) * ( 1.0 + (bots.length - 26) * 0.1 ));
}
return storage.energyConsumptionRate;
},
}
로빈 후드
{
"Robin Hood": function(dist, energy, bots, storage) {
if (!dist)
storage.move = [
[100, 1],
[200, Math.sqrt(192 / 49) - 0.00695],
[10000 / 49, (100 / 49)]
].sort((a, b) => Math.abs(a[0] - energy) - Math.abs(b[0] - energy))[0][1];
return storage.move;
}
}
이 봇은 레이스에서 다음 세 가지 작업 중 하나를 수행합니다.
- 턴당 하나의 유닛 이동 : 각 게임의 첫 번째 레이스에서 필요한 에너지를 모두 확보하기 위해이 작업을 수행합니다.
- 턴당 두 유닛보다 약간 느리게 이동 : 이 작업은 매 턴마다 수행되며 에너지를 절약하여 다음을 수행 할 수 있습니다.
- 턴당 2 유닛보다 약간 더 빠르게 이동 : 현재 경쟁자보다 한 턴 더 빠르게 완료 할 수 있으며 이전 승자 몇 명을 간신히 언더컷 할 수 있습니다 (게시 시점에서 비율 제어가 100 분의 1 포인트 앞서 있음).
수집기
{
"Collector": function(dist, energy, bots, storage) {
if (!dist) {
if ("turns" in storage) {
storage.avg = ((storage.avg * Math.max(storage.races++, 0)) + storage.turns) / Math.max(storage.races, 1);
} else {
storage.avg = 100;
storage.races = -1;
}
storage.turns = 0;
storage.move = (energy >= 10000 / (storage.avg | 0)) ? (100 / (storage.avg | 0)) : 0.5;
}
storage.turns++;
return storage.move;
}
}
수집가는 기본적으로 0.5 단위 / 턴의 속도로 이동합니다. 이것은 에너지 수집에 최적입니다. 레이스가 시작될 때 가지고있는 에너지로 평균을 동점 또는 이길 수 있다고 예측하면 그렇게하려고합니다.
현재 속도 제어에 실패하지만 새로운 전략에 더 잘 적응할 수 있습니다.
Greedy / Greedier
{
"Greedy": function(dist, energy, bots, storage) {
return energy > 100 ? 2 : 1;
},
"Greedier": function(dist, energy, bots, storage) {
return dist + energy > 100 ? 2 : 1;
},
}
Greedy는 에너지가 100 이상이면 턴당 2 유닛을 이동하고 그렇지 않으면 턴당 1 유닛을 이동합니다. Greedier는 각 끝에 충분한 에너지가있을 것이라고 생각하면 턴당 2 유닛을 이동합니다. 그렇지 않으면 턴당 1 유닛을 이동합니다. 이것은 봇이 가질 수있는 보너스 에너지를 사용하는 것에 대해 제가 생각할 수있는 가장 간단한 방법이었습니다.
계산 된 스프린터
계산 된 스프린터는 현재 연료가 남아있는 상태에서 최대한 빨리 전체 랩을 실행하려고합니다. 미래의 경주를 계획 할만큼 똑똑하지 않은 사람은 달리기 위해 여기에있는 것만으로도 행복합니다.
{
"Calculated Sprinter": function(dist, energy, bots, storage){
var remaining = 100-dist;
var energyLeftPerUnit = energy/remaining;
return Math.sqrt(energyLeftPerUnit)
}
}
(신규) 가속
{
"Accelerate": function(dist, energy, bots, storage) {
return dist * 0.21 + 0.001;
},
}
진정하세요, 저는 단지 매우 단순한 봇으로 실험하고 있습니다.
이 봇은 이해하기 매우 쉽습니다. 처음에는 0.001 속도로 실행되고 2 차적으로 가속됩니다.
나는 임의성을 좋아한다
{
"I love Randomness": function(dist, energy, bots, storage) {
storage.rand = Math.abs(dist ^ energy ^ storage.rand) + 1;
return Math.abs(dist ^ energy ^ storage.rand) + 1;
}
}
서프라이즈 / 타이밍
"Timing": function(dist, energy, bots, storage) {
storage.turns = storage.turns || 0;
storage.games = storage.games || 0;
storage.turns++;
if(dist == 0) {
storage.games++;
estimated_game_length = Math.ceil( storage.turns / storage.games)+2;
desired_speed = 100 / estimated_game_length;
max_speed = Math.sqrt( energy / estimated_game_length);
storage.speed = Math.min(desired_speed, max_speed);
}
if(storage.games < 3)
return storage.games;
return storage.speed;
},
"Surprise": function(dist, energy, bots, storage) {
storage.turns = storage.turns || 0;
storage.games = storage.games || 0;
storage.turns++;
if(dist == 0) {
storage.games++;
estimated_game_length = Math.ceil( storage.turns / storage.games);
desired_speed = 100 / (estimated_game_length - 3);
max_speed = Math.sqrt( energy / estimated_game_length);
if(desired_speed <= max_speed) {
storage.speed = desired_speed;
}
else {
storage.speed = Math.min(2, max_speed);
}
}
if(storage.games < 3)
return storage.games;
return storage.speed;
}
일반적으로 게임이 얼마나 오래 지속되는지에 따라 고정 속도를 계산합니다. 그런 다음 타이밍은 목표를 맞추려고 시도하고 Surprise는이를이기려고합니다.
이 두 가지를 모두 사용하여 테스트를 실행하는 동안이 KotH의 공모에 대한 규칙이 필요하다는 것이 분명해졌습니다. Surprise는 자신의 점수를 희생하여 레이스 길이를 줄임으로써 Timing이 훨씬 더 잘할 수 있도록 만들 수 있으며, Timing이 알고있는 고정 된 간격으로 만 그렇게함으로써 더 많은 도움을 줄 수 있습니다.
나는 그들이 정신에 있지 않다고 생각하기 때문에 지금 이러한 헛소리를 당기지 않습니다.
모방
{
"Mimic": function(dist, energy, bots, storage) {
if (!dist) {
storage.last = bots;
storage.rand = energy ** 3;
return energy / (100 - dist);
}
storage.rand = Math.abs(dist ^ dist ** 2 ^ energy ^ energy ** 3 ^ energy ** 5 ^ bots.reduce((s, b) => s + b, 0) ^ storage.rand * (2 ** 31)) / (2 ** 31);
var result = bots.map((b, i) => b - storage.last[i])[storage.rand * bots.length | 0]; // Fix RNG
storage.last = bots;
return Math.max(Math.min(result, Math.sqrt(energy / ((100 - dist) / 4))), Math.sqrt(energy / ((100 - dist))));
}
}
마지막 턴에 다른 모든 봇의 (효과적인) 이동 목록을 만들고 HighlyRadioactive의 PRNG의 더 나은 버전을 사용하여 의사 난수를 선택합니다. 이 값이 특정 범위 (약 절반 정도 발생) 내에 있는지 확인하므로 어리석은 일을하지 않습니다.
빠르고 안정적이지 않음
{
"Fast and not steady": function() {
return 99999999;
}
}
느린 것보다 빠름
{
"Faster than Slow": function() {
return 2;
}
}
이것이 나쁜 봇이라고 생각한다면 아니오.
Faster than Slow 48.951
전부의
Whole은 분수 거리를 좋아하지 않으며 항상 정수 거리를 이동합니다.
"Whole": function(dist, energy, bots, storage) {
if (dist == 0) {
if (energy < 110) {
storage.lambda = function(distance) {return 100 - distance - 1;}
storage.step = 1
}
else {
storage.lambda = function(distance) {return 200 - distance - 2;}
storage.step = 2
}
}
let expEnergyPast = storage.lambda(dist);
if (expEnergyPast + (storage.step + 1) ** 2 <= energy) {
return storage.step + 1;
}
return storage.step;
}
```
사십 구
Fourty-Nine은 Winner & Winner2를 살펴본 결과 49 턴에서 승리하는 것이 48 턴보다 낫다는 것을 인식했습니다. 하지만 Fourty-Nine은 당신의 규칙에 따라 이기기를 원합니다. 따라서 Fourty-Nine은 많은 레이스에서 우승하기 위해 거리를 희생하지 않습니다. 그러나 승리하기 위해 49 턴보다 빨리 갈 수는 없습니다.
"fourty-nine": function(dist, energy, bots, storage) {
if (dist == 0) {
if (energy < 110) {
storage.step = 1
}
else if(energy < 10000.0/49){
storage.step = 2
}
else {
storage.step = 100.0/49
}
}
return storage.step;
},
예언자
{
"Predictor": function(dist, energy, bots, storage) {
if (!dist)
if (energy == 100)
storage.move = 1;
else
storage.move = (energy >= 10000 / (50 - bots.length * 0.25 | 0)) ? (100 / (50 - bots.length * 0.25 | 0)) : 1.3;
return storage.move;
}
}
Predictor는 더 많은 봇이 추가 될수록 더 빨리 승리해야한다고 가정합니다. 시간이 지남에 따라 에너지를 수집 한 다음 상자 속의 수집기 또는 잭과 유사한 방식으로 결승선을 향해 질주합니다.
결정 3M8
다르게 작동 하는 UWUTM8의 개선
누군가가 과속을 할 때를 예측하고 더 많은 포인트를 얻기 위해 더 많은 에너지를 사용하려고합니다.
"DECISION3M8": function(dist, energy, bots, storage) {
const checkpointPer = 5;
if (storage.turn == undefined) {
storage.turn = 0;
} else {
storage.turn = storage.turn + 1;
}
if (dist === 0) {
if (storage.round == undefined) {
storage.round = 0;
}
storage.round = storage.round + 1;
storage.turn = 0;
storage.maxAtPreviouscheckpoint = 0;
storage.predictedTurnsLeft = 100;
storage.travelSpeed = Math.sqrt(energy / 50);
if (energy == 100) {
return 1;
}
} else if (storage.turn % checkpointPer == 0) {
let maxAtCurrentTurn = Math.max( ...bots );
let speederCheck = maxAtCurrentTurn / (storage.turn / checkpointPer) - storage.maxAtPreviouscheckpoint / ((storage.turn / checkpointPer) - 1);
let speedOfSpeederPerTurn = maxAtCurrentTurn / storage.turn;
if ((Math.abs(speederCheck) < 0.01) && (maxAtCurrentTurn > dist)) {
//console.log(speederCheck);
storage.predictedTurnsLeft = Math.ceil(100 / speedOfSpeederPerTurn) - (100 - storage.turn);
storage.travelSpeed = Math.sqrt(energy / (storage.turn - speedOfSpeederPerTurn));
//console.log(storage.predictedTurnsLeft);
}
}
return storage.travelSpeed;
}
우승자
우승자는 당신의 규칙에 관심이 없습니다. 승자는 자체 규칙에 따라 플레이합니다.
우승자는 가능한 한 많은 레이스에서이기려고합니다 (= 거리 100에서 끝남).
"Winner": function(dist, energy, bots, storage) {
if (dist == 0) {
if (energy < 10000.0/49) {
storage.step= 0.5;
}
else {
storage.step = 100.0/49;
}
}
return storage.step;
},
"Winner2": function(dist, energy, bots, storage) {
if (dist == 0) {
if (energy < 10000.0/48) {
storage.step= 0.5;
}
else {
storage.step = 100.0/48;
}
}
return storage.step;
},
```
UWUTM8
많은 봇과 마찬가지로 가능한 한 머치 에너지를 사용하여 최대한 빨리 끝내려고합니다. 또한 특정 점수에서 전혀 끝내려고하지 않고 9 점에 도달하려고합니다.
"UWUTM8": function(dist, energy, bots, storage) {
if (dist === 0) {
if (storage.round == undefined) {
storage.round = 0;
}
storage.round = storage.round + 1;
if (storage.round % 2500 == 0 || storage.round == 250 || storage.round == 750) {
storage.travelSpeed = Math.sqrt(energy / 90)
} else {
storage.travelSpeed = Math.sqrt(energy / 100)
}
}
return storage.travelSpeed;
}