Колекціонер золота KoTH


48

Примітка. Незабаром буде опубліковано опитування для улюбленого спільноти

У цьому KoTH мета - бути останнім живим ботом. Монети будуть розміщені у випадкових місцях, і ваш бот повинен отримати монети першими. Якщо бот натрапив на іншого бота, бот з більшою кількістю монет виграє, а інший бот гине. Детальніше нижче.

Типи монет

Буде 2 види монет: золота та срібна. Золото додає 5 монет міцності бота, а срібло - 2. Коли монета зібрана, інша монета розміщується на іншому місці на дошці. У будь-який момент часу на арені є одна золота і чотири срібних монети.

Зіткнення ботів

У випадку, коли два боти намагаються зайняти один і той же простір, той, у якого більше монет, залишиться, а той, у якого менше, буде… ні. Бот, який виграє, набере 85% монет опонентів (Закруглені). Якщо вони пов'язані, обидва гинуть. Якщо три або більше намагаються зайняти один і той же простір, виграє найпотужніший і отримує 85% усіх монет інших ботів. У випадку, якщо найпотужніший бот - краватка, всі боти гинуть, хто намагався увійти в космос.

Арена

Довжина сторони арени обчислюється за допомогою 4 + botCount. При розміщенні ботів на початку гри вибираються випадкові місця. Система гарантує, що жоден бот не запускається в одному просторі або поруч один з одним. Монети генеруються випадковим чином, виключаючи квадрат 3 по 3 на кожному боті. Якщо бота знайшли поза ареною, він вмирає миттєво. Арена починається з (0,0), або Північно-Західного, у лівому верхньому куті, і розташування бота завжди є цілим числом.

Ваш бот

Ваш бот повинен бути функцією на будь-якій об'єктно-орієнтованій мові, що має масиви, цілі числа, рядки та функції. Зауважте, що всі подання будуть перетворені на Javascript, щоб зробити речі простішими. Щоб зберігати інформацію між рухами, використовуйте botNotes.storeData(key, value)та botNotes.getData(key, value). Ви не можете зберігати або отримувати доступ до даних будь-яким іншим способом, крім того, який надається через параметри та botNotes. Ви повинні створити функцію , яка при виклику, повертає рядок north, east, south, west, або none. Існує 3 аргументи для функції:

  • Об'єкт з чотирма цілими числами ( locationX, locationY, coins, arenaLength), ваше місце свого перебування, ваші монети, а довжина арени

  • Багатовимірний масив з координатами X і Y інших ботів та їх кількістю монет, наприклад,[[0,5,4],[4,7,1],[7,4,12]]

  • Масив із переліченими місцями монет (золото завжди перше)

Це виклик короля пагорба, заборонені стандартні лазівки . Ваша функція буде виконуватися кілька тисяч разів, кожен раз дозволяючи один "Move". Зауважте, що якщо гра перевищує 20 000 ходів , виграє бот з найбільшою кількістю монет. Це буде зроблено 8000 разів, щоб усунути випадковість.

Чат: https://chat.stackexchange.com/rooms/81347/gold-collectors-koth

Призи:

Перше місце:
улюбленість спільноти у 100 балів : відповідь у 15 балів

Переможці:

Перше місце: TBTPTGCBCBA
Друге місце: Big King Little Hill
Третє місце: потенційно переможене
четверте місце: ввічливий недалекоглядний п'яний бот
П'яте місце: монета безпеки


6
"Зауважте, що всі подання будуть перетворені на Javascript, щоб зробити речі простішими." Як це має працювати? Ви робите конверсію?
Лайконі

21
Немає нічого поганого в тому, що кот дозволяє лише одну мову, особливо таку, яка широко поширена як JavaScript. Замість того, щоб неоднозначно "перетворювати" відповіді на JavaScript (імовірно, самі та вручну), ви повинні просто обмежити виклик лише JS. Зрештою, у нас було чимало котів, лише для Java та Python.
Skidsdev

2
Версія цього, де ви керуєте прискоренням замість положення, була б досить прикольною.
akozi

12
Всім: Уже є занадто багато коментарів. Не залишайте марних коментарів, таких як "+1, хороший бот" , і, будь ласка, видаліть свої коментарі, якщо вони зайві . Ми не типовий сайт із запитаннями, але ніхто не любить читати сотні команд.
користувач202729

5
(На моє власне питання): Відповідно до NP у чаті, це останнє: всі боти рухаються, потім вирішуються всі конфлікти, потім відбуваються всі підхоплення монет, потім розміщуються всі нові монети.
BradC

Відповіді:


26

BaitBot - JavaScript Node.JS

Навіщо турбуватися переслідувати чи бігати, якщо ніколи не можеш зловити? Натомість BaitBot знаходить найближчу монету і чекає, коли слабший бот також підійде до неї. Коли вони обидва суміжні, baitBot йде за монету, припускаючи, що і слабший бот. Якщо baitBot чекає і підходить сильніший бот, він просто хапає монету і скачує. Спробуй мене!

function baitBot(me, others, coins) {
  let directions = ['none','east','south','west','north']
  function distanceTo(a) {
    return (Math.abs(a[0] - me.locationX) + Math.abs(a[1] - me.locationY))
  }
  function distanceBetween(a, b){
    return (Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]))
  }
  function adjacentDir(a) {
    //0 = no, 1,2,3,4 = ESWN
    if(distanceTo(a) == 1) {
      if(a[0] > me.locationX){ return 1}
      else if(a[0] < me.locationX) {return 3}
      else if(a[1] > me.locationY) {return 2}
      else{ return 4}
    }
    else {return 0}
  }
  function edibility(a) {
    return me.coins - a[2]
  }

  //Find nearest coin and get next to it
  let closestCoin = coins.sort((a,b) => distanceTo(a) - distanceTo(b))[0]
  if(distanceTo(closestCoin) > 1) {
    if(closestCoin[0] > me.locationX){ return 'east'}
    else if(closestCoin[0] < me.locationX){ return 'west'}
    else if(closestCoin[1] < me.locationY){ return 'north'}
    else if(closestCoin[1] > me.locationY){ return 'south'}
  }

  //If we're next to a coin and there's a threat close, just grab it
  let nearestThreat = others.filter(a => edibility(a) < 0).sort((a,b) => distanceBetween(a, closestCoin) - distanceBetween(b, closestCoin))[0]
  if(nearestThreat && distanceBetween(nearestThreat, closestCoin) <= 2) {
    return directions[adjacentDir(closestCoin)]
  }



  //Otherwise, wait until there's a target also next to the coin. If none are close, just take it
  let targets = others.filter(a => edibility(a) > 0 && distanceBetween(closestCoin, a) <= 3)
  targets.sort((a,b) => distanceBetween(a, closestCoin) - distanceBetween(b, closestCoin))
  if(targets.length > 0 && distanceBetween(targets[0], closestCoin) > 1){
    return directions[0]
  }
  return directions[adjacentDir(closestCoin)]

}

1
Ха, це акуратна ідея, мені це подобається.
sundar

Цей підхід досить класний ... ні, дуже круто
програми Redwolf

1
BaitBot потребує, nearestThreat && distanceTo(nearestThreat)а не просто distanceTo(nearestThreat). Він провалюється, коли загрози немає.
Програми Redwolf

1
Так, nearestThreatце undefinedякщо всі інші боти мають більше очок , ніж у вас.
Ніч2

1
Ну, я отримую сповіщення, як [10] Bot Bait Bot tired of this world, and jumped off its edgeу своєму журналі журналів
Redwolf Programs

17

Потенційно переможний | JavaScript

Кращим кольором для цього бота є #1600a6.

function (me, others, coins)
{
    let huntingTimer = botNotes.getData("huntingTimer");
    let huntedIndex = botNotes.getData("huntedIndex");
    if(!huntingTimer)
    huntingTimer = 0;
    else if(huntingTimer >0)
    huntingTimer--;
    else if(huntingTimer == -1)
    huntingTimer = Math.ceil(20*(1+Math.log2(me.coins/25)));
    else
    huntingTimer++;

    function distanceFromMe(X, Y) { return Math.abs(me.locationX - X) + Math.abs(me.locationY - Y); }

    function U(x, y)
    {
    function distance(X, Y) { return Math.abs(X-x) + Math.abs(Y-y); }
    function gravitation(k, X, Y) { return - k / ( distance(X, Y) + .2 ); }
    function exponential(k, q, X, Y) { return - 5*k * Math.exp(- q * distance(X,Y)); }

    // No going away from the arena.
    if(!((0 <= x) && (x < me.arenaLength) && (0 <= y) && (y < me.arenaLength)))
    {
        return Infinity;
    }

    let reachability = [1, 1, 1, 1, 1];
    let distances = coins.map(c => distanceFromMe(c[0], c[1]));
    for(let i = 0; i < others.length; i++)
    {
        for(let coin = 0; coin < 5; coin++)
            reachability[coin] += (Math.abs(others[i][0] - coins[coin][0]) + Math.abs(others[i][1] - coins[coin][1])) < distances[coin];
    }

    let potential = gravitation(40, coins[0][0], coins[0][1]) / (reachability[0]); // Gold

    // Silver
    for(let i = 1; i < 5; i++)
    {
        potential += gravitation(10, coins[i][0], coins[i][1]) / (reachability[i]);
    }

    others.sort((a, b) => b[2] - a[2]);

    // Other bots
    for(let i = 0; i < others.length; i++)
    {
        if(
            ((Math.abs(me.locationX - others[i][0]) + Math.abs(me.locationY - others[i][1])) < 3) &&
            (huntingTimer == 0) &&
            (me.coins > 25) && 
            (me.coins < (others[0][2]*.9)) &&
            (others[i][2] < me.coins-5) && (others[i][2] >= 10)
        )
        {
            huntingTimer = -10;
            huntedIndex = i;
        }

        if((huntingTimer < 0) && (huntedIndex == i))
           potential += exponential(30, 1, others[i][0], others[i][1]);

        if(others[i][2] >= me.coins)
        {
        // Otherwise, they could eat us, and we will avoid them.
        potential += exponential(-1400, 3, others[i][0], others[i][1]);
        }
    }

    return potential;
    }

    // All possible squares we can move to, with their names.
    let movements = [
    [ "north", U(me.locationX, me.locationY - 1)],
    [ "south", U(me.locationX, me.locationY + 1)],
    [ "east", U(me.locationX + 1, me.locationY)],
    [ "west", U(me.locationX - 1, me.locationY)],
    [ "none", U(me.locationX, me.locationY)]
    ];

    botNotes.storeData("huntingTimer", huntingTimer);
    botNotes.storeData("huntedIndex", huntedIndex);

    // Sort them according to the potential U and go wherever the potential is lowest.
    movements.sort((a, b) => a[1] - b[1]);
    return movements[0][0];
}

.

Грубе пояснення

Я відмовляюся у спробі оновити пояснення формул. Коефіцієнти постійно змінюються, і так важко постійно уточнювати пояснення. Тож я просто поясню загальний принцип.

Кожна монета та кожен бот генерують силове поле з певним потенціалом. Я просто додаю потенціали з усього разом, і бот потім йде туди, де потенціал найнижчий. (Очевидно, ця ідея вкрадена у фізики.)

Я використовую два види потенціалів. Перший - це псевдогравітаційний (який діє в будь-якому діапазоні), з Доє «сила» поля, і при такому виборі знака, потенціал є привабливим. Гтут (і скрізь) це відстань в метриці таксомотора,г = | x₁ - x₂ | + | y₁ - y₂ | .

U=kr+1511+n.

Я використовую k = 40 для золотих монет і k = 10 для срібних монет. n - кількість ботів, які ближче до певної монети, ніж ми. В іншому випадку ми абсолютно ігноруємо інших ботів (якщо ми заважаємо сильнішому боту, ми тікаємо, але це все). Я ціную золотих монет більше, ніж вони коштують, бо в іншому випадку боти, які йдуть насамперед після золота, весь час били мене.

Другий потенціал - це експоненціально занепад (який ефективно діє лише на дуже малих відстанях). Це породжується іншими, переважно більш потужними, ботами.

Вони дають поле з Ця сила непомірно сильна на дальності 0-1, але на більших відстанях майже не знижується. (Відстань + 1 означає різання сили на 1/20.)

U=5×1400e3r.

Ми, як правило, не нападаємо на інших ботів навмисно (звичайно, якщо вони заважають нам, і ми наступаємо на них, це їхня вина), але є можливість зробити це. Якщо деякі жорсткі умови будуть виконані, ми можемо перейти в режим полювання , зосереджуючись на одному боті. Щоб увійти в режим полювання:

  1. У нас повинно бути не менше 25 монет. (Нам потрібно спочатку дістати кілька монет.)
  2. Вони повинні мати максимум (у нас - 5 монет ) і не менше 10 монет. (Ми не хочемо полювати на когось, хто хапає одну монету і раптом стає більш потужним, і ми також не хочемо переслідувати ботів з нульовими монетами.)
  3. Ми повинні відставати від поточного провідного бота принаймні на 1/10 його монет. (Щоб полювати на щось, вам пощастить, тому немає потреби дарувати гарну позицію лише для того, щоб спробувати нашу удачу.)
  4. Ми не повинні знаходитись на охороні (див. Нижче).

Якщо все це задоволено, активується режим полювання. Протягом наступних 10 раундів загнаний бот випромінює лише потенціал

U=150er.
Після закінчення цих 10 патронів ми переходимо до охолодження, під час якого ми можемо знову не перейти в режим полювання. (Це означає, щоб не допустити, щоб ми нескінченно і безрезультатно переслідували одного бота, а всі інші радісно захоплювали монети.) Захоплення охоти складає 20 патронів, коли у нас є 25 монет, і збільшується на 20 монет за кожне подвоєння цього. (Іншими словами, припинення дії - це20(1 + log2(c / 25)).) (Ми використовуємо це тому, що в кінцевій грі всі мисливські боти, швидше за все, мертві, і тому будь-яке полювання буде, ймовірно, марним. Через це ми хочемо обмежити витрачений час. Але іноді щасливий пізній- Ігрове харчування може змінити все, тому ми зберігаємо можливість.)

Нарешті, всю арену розміщують у нескінченному потенційному колодязі, що запобігає втечі бота.


Я думаю, що цей бот, ймовірно, вибиває і мій зважений рух.
fəˈnɛtɪk

@ fəˈnɛtɪk - Так і роблю :—). Я думаю, що цей може впоратися з іншими ботами трохи краще. (Крім того, це не "засліплене" монетою на сусідній площі.) Але я напевно дав вам +1, бо я величезний фанат цієї ідеї.
Раміллі

Чи можете ви застосувати до цього принцип найменшої дії?
Бета-розпад

@BetaDecay: Не зовсім боюся, обчислення не дуже добре реагує на дискретні проблеми, як це. Навіть у безперервному випадку це не було б тривіально (через фіксовану величину швидкості), але це могло бути здійснено після деяких магічних полярних координат.
Раміллі

4
Це круто. Я не впевнений, що ризик монотонно пов'язаний з дистанцією, але здається, що загроза на відстані 2 простору швидше вб'є вас, ніж один сусідній, оскільки в останньому випадку одному з вас потрібно залишатися нерухомим, щоб сталося зіткнення.
Каїн

16

Алгоритм навчання першого роду | JavaScript (Node.js)

function run() {
	return ['north','east','south','west'][(Math.random()*4)|0];
}

Спробуйте в Інтернеті!

Ви коли-небудь бачили ті часові проміжки навчання алгоритмів навчання грати в гру? Вони часто рухаються майже безладно в перші кілька поколінь ...


ЛОЛ ... Це все одно може працювати!
Програми Redwolf

2
Більшість алгоритмів навчання працюють буквально випадковими для перших кількох ітерацій, а не майже майже випадковим чином.
fəˈnɛtɪk

Вгадай що? Цей бот в середньому отримав майже 0,22 монети за раунд!
Програми Redwolf

16

Великий король Маленький пагорб | JavaScript

function BigKingLittleHill(me, enemies, coins) {

	
	// Is a move safe to execute?
	function isItSafe(x){
			let loc = [x[0] + me.locationX,x[1] + me.locationY];
			return loc[0] >= 0 && loc[0] < me.arenaLength
			&& loc[1] >= 0 && loc[1] < me.arenaLength
			&& enemies
					.filter(enemy => me.coins <= enemy[2])
					.filter(enemy => getDist(enemy,loc) == 1).length === 0;
	}

	
	// Dumb conversion of relative coord to direction string
	function coordToString(coord){
		if (coord[0] == 0 && coord[1] == 0) return 'none';
		if (Math.abs(coord[0]) > Math.abs(coord[1]))
			return coord[0] < 0 ? 'west' : 'east';
		return coord[1] < 0 ? 'north' : 'south';
	}
	
	
	// Calculate a square's zone of control
	function getZOC(x) {
		let n = 0;
		for(let i = 0; i < me.arenaLength;i++){
			for(let j = 0; j < me.arenaLength;j++){
				if (doesAControlB(x, [i,j])) n++;
			}
		}
		return n;
	}
	
	function doesAControlB(a, b) {
		return getEnemyDist(b) > getDist(a, b);
	}
  
	// Distance to nearest enemy
	function getEnemyDist(x) {
			return enemies.filter(enemy => enemy[2] >= me.coins/50).map(enemy => getWeightedDist(enemy, x)).reduce((accumulator, current) => Math.min(accumulator, current));
	}
  
	// Weights distance by whether enemy is weaker or stronger
	function getWeightedDist(enemy, pos) {
		return getDist(enemy, pos) + (enemy[2] < me.coins ? 1 : 0);
	}
  
	function getDist(a, b){
		return (Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]))
	}
	
	//check whether there are coins in our Zone of Control, if yes move towards the closest one
	let loc = [me.locationX,me.locationY];
	let sortedCoins = coins.sort((a,b) => getDist(loc,a) - getDist(loc,b));
	for (let coin of sortedCoins) {
		if (doesAControlB(loc,coin)){
			return coordToString([coin[0] - loc[0],coin[1] - loc[1]]);
		}
	}
	
	//sort moves by how they increase our Zone of Control
	northZOC = [[0,-1], getZOC([loc[0],loc[1]-1])];
	southZOC = [[0,1], getZOC([loc[0],loc[1]+1])];
	westZOC = [[-1,0], getZOC([loc[0]-1,loc[1]])];
	eastZOC = [[1,0], getZOC([loc[0]+1,loc[1]])];
	noneZOC = [[0,0], getZOC([loc[0],loc[1]])];
	let moves = [northZOC,southZOC,westZOC,eastZOC,noneZOC].sort((a,b) => b[1] - a[1]);
	
	//check whether these moves are safe and make the highest priority safe move
	for (let move of moves) {
		if (isItSafe(move[0])) { 
			return coordToString(move[0]);
		}
	}
	//no moves are safe (uh oh!), return the highest priority
	return coordToString(moves[0][0])
}

Спробуйте в Інтернеті!

Big King Little Hill приймає рішення на основі "зон контролю". Він буде переслідувати лише монети, які знаходяться в зоні контролю, тобто він зможе дістатися до монети раніше, ніж зможе будь-який інший бот. Коли в його зоні управління немає монет, вона замість цього рухається, щоб максимально збільшити розмір зони контролю. Великий Кінг Літл Хілл обчислює зону контролю кожного з 5 можливих рухів і надає перевагу рухам, які максимально збільшують розмір зони контролю. Таким чином Big King Little Hill зрештою досягає локального максимуму (маленького пагорба) контролю і чекає, коли в його зоні буде створена монета. Крім того, Big King Little Hill відкидає будь-який крок, який може призвести до його смерті, якщо не буде альтернативи.

Big King Little Hill - песиміст (він вважає за краще термін реаліст), оскільки не турбується оскаржувати будь-яку монету, яку не запевняють. Це також пацифіст, оскільки він не переслідує більш слабких ботів у будь-якому сенсі (хоча він може наступити на одного, якщо їм заважатимуть). Нарешті, Big King Little Hill - боягуз, який не загрожує власному життю за будь-яку винагороду, якщо цього абсолютно не доведеться.


1
Ласкаво просимо до PPCG! Це дуже хороший бот = D
Luis felipe De jesus Munoz

Це те, що я думав про бота. Хороша робота.
Джо.

10

Монета безпеки | JavaScript

SafetyCoin=(myself,others,coins)=>{
  x=myself.locationX;
  y=myself.locationY;
  power=myself.coins;
  arenaSize=myself.arenaLength;
  dist=0;
  optimalCoin=7;
  optimalDist=11*arenaSize;
  for(i=0;i<coins.length;i++){
    enemyDist=3*arenaSize;
    dist=Math.abs(x-coins[i][0])+Math.abs(y-coins[i][1])
    for(j=0;j<others.length;j++){
      if(i==0){
        if(others[j][2]+5>=power){
          enemyDist=Math.min(enemyDist,Math.abs(others[j][0]-coins[i][0])+Math.abs(others[j][1]-coins[i][1]))
        }
      }
      else{
        if(others[j][2]+2>=power){
          enemyDist=Math.min(enemyDist,Math.abs(others[j][0]-coins[i][0])+Math.abs(others[j][1]-coins[i][1]))
        }
      }

    }
    if(enemyDist>dist){
      if(i==0){
        if(dist/5<optimalDist){
          optimalDist=dist/5;
          optimalCoin=i;
        }
      }
      else{
        if(dist/2<optimalDist){
          optimalDist=dist/2;
          optimalCoin=i;
        }
      }
    }
  }
  if(optimalCoin==7){
    safeDir=15;
    if(x==0){safeDir-=8;}
    if(x==arenaSize-1){safeDir-=2;}
    if(y==0){safeDir-=1;}
    if(y==arenaSize-1){safeDir-=4;}
    for(i=0;i<others.length;i++){
      if(others[i][2]>=power){
        if(Math.abs(x-others[i][0])+Math.abs(y-others[i][1])==2){
          if(x-others[i][0]>0){safeDir-=8;}
          if(x-others[i][0]<0){safeDir-=2;}
          if(y-others[i][1]>0){safeDir-=1;}
          if(y-others[i][1]<0){safeDir-=4;}
        }
      }
    }
    directions=["north","east","south","west"];
    if(safeDir!=0){
      tmp="";
      tmp+="0".repeat(Math.max(Math.sqrt(arenaSize)/2|0,y-(arenaSize/2|0)));
      tmp+="2".repeat(Math.max(Math.sqrt(arenaSize)/2|0,(arenaSize/2|0)-y));
      tmp+="1".repeat(Math.max(Math.sqrt(arenaSize)/2|0,(arenaSize/2|0)-x));
      tmp+="3".repeat(Math.max(Math.sqrt(arenaSize)/2|0,x-(arenaSize/2|0)));
      rnd=tmp[Math.random()*tmp.length|0];
      while(!(2**rnd&safeDir)){rnd=tmp[Math.random()*tmp.length|0];}
      return directions[rnd];
    }
    return "none";//the only safe move is not to play :P
  }
  distX=coins[optimalCoin][0]-x;
  distY=coins[optimalCoin][1]-y;
  if(Math.abs(distX)>Math.abs(distY)){
    if(distX>0){return "east";}
    else{return "west";}
  }
  else{
    if(distY>0){return "south";}
    else{return "north";}
  }
}

Цей бот прямує прямо до зваженої монети (значення / відстань), від якої не може померти, досягнувши одночасно або після іншого бота. Якщо немає справжньої монети з цим властивістю, вона сидить там, де це бот, тепер рухається у випадковому безпечному напрямку (безпека означає, що якщо бот рухається до неї, захисна монета не може зіткнутися. Це дозволяє боту міняти місця іншим ботом, якщо безпосередньо поруч із ним), зваженим у напрямку до центру арени.


1
Так, це може перемогти. Хоча, ботів дуже багато
Redwolf Programs

Цей метод матиме більше проблем, чим більш нерівномірно розміщуються ворожі боти з більшим або рівним значенням.
fəˈnɛtɪk

1
Що ж, вони, мабуть, всі зроблять рейс до найближчої до них монети / золотої монети.
Програми Redwolf

Це буде добре лише в тому випадку, якщо йому вдасться отримати трохи монет на початку.
fəˈnɛtɪk

І це здебільшого удача, оскільки місце, де створюються монети, визначається випадковим чином
програми Redwolf

10

Бот, який грає в гру обережно, але може бути агресивним | JavaScript

Бажаний колір: #F24100

Примітка: Хоча цей бот зайняв 1-е місце, це пов’язано з об'єднанням з "Феодальним дворянством" наприкінці та з'їданням його за більше монет. Інакше цей бот був би 3-м. Якщо вас цікавлять боти, які є більш потужними в індивідуальному порядку, огляньте потенційно переможні та Big King Little Hill .

function (me, monsters, coins) {
    var i, monstersCount = monsters.length, phaseSize = Math.round((me.arenaLength - 4) / 4),
        center = (me.arenaLength - 1) / 2, centerSize = me.arenaLength / 4,
        centerMin = center - centerSize, centerMax = center + centerSize, centerMonsters = 0, centerMonstersAvg = null,
        end = 2e4, apocalypse = end - ((me.arenaLength * 2) + 20), mode = null;

    var getDistance = function (x1, y1, x2, y2) {
        return (Math.abs(x1 - x2) + Math.abs(y1 - y2)) + 1;
    };

    var isAtCenter = function (x, y) {
        return (x > centerMin && x < centerMax && y > centerMin && y < centerMax);
    };

    var round = botNotes.getData('round');
    if (round === null || !round) round = 0;
    round++;
    botNotes.storeData('round', round);

    var isApocalypse = (round >= apocalypse && round <= end);
    if (isApocalypse) {
        mode = botNotes.getData('mode');
        if (mode === null || !mode) mode = 1;
    }

    for (i = 0; i < monstersCount; i++) if (isAtCenter(monsters[i][0], monsters[i][1])) centerMonsters++;

    var lc = botNotes.getData('lc');
    if (lc === null || !lc) lc = [];
    if (lc.length >= 20) lc.shift();
    lc.push(centerMonsters);
    botNotes.storeData('lc', lc);

    if (lc.length >= 20) {
        centerMonstersAvg = 0;
        for (i = 0; i < lc.length; i++) centerMonstersAvg += lc[i];
        centerMonstersAvg = centerMonstersAvg / lc.length;
    }

    var getScore = function (x, y) {
        var score = 0, i, chaseFactor = 0.75, coinFactor = 1;

        if (monstersCount < phaseSize) {
            chaseFactor = 0;
            coinFactor = 0.25;
        } else if (monstersCount < phaseSize * 2) {
            chaseFactor = 0;
            coinFactor = 0.5;
        } else if (monstersCount < phaseSize * 3) {
            chaseFactor = 0.5;
            coinFactor = 0.75;
        }

        if (isApocalypse) {
            if (mode === 1) {
                var centerDistance = getDistance(x, y, center, center);
                if (centerDistance <= 3) {
                    mode = 2;
                } else {
                    score += 5000 / (centerDistance / 10);
                }
            }
            if (mode === 2) chaseFactor = 1000;
        }

        for (i = 0; i < monstersCount; i++) {
            var monsterCoins = monsters[i][2], monsterDistance = getDistance(x, y, monsters[i][0], monsters[i][1]);
            if (me.coins > monsterCoins && monsterDistance <= 3) {
                score += (Math.min(5, monsterCoins) * chaseFactor) / monsterDistance;
            } else if (me.coins <= monsterCoins && monsterDistance <= 3) {
                score -= (monsterDistance === 3 ? 50 : 10000);
            }
        }

        for (i = 0; i < coins.length; i++) {
            var coinDistance = getDistance(x, y, coins[i][0], coins[i][1]),
                coinDistanceCenter = getDistance(center, center, coins[i][0], coins[i][1]),
                coinValue = (i === 0 ? 250 : 100), coinCloserMonsters = 0;

            for (var j = 0; j < monstersCount; j++) {
                var coinMonsterDistance = getDistance(monsters[j][0], monsters[j][1], coins[i][0], coins[i][1]);
                monsterCoins = monsters[j][2];

                if (
                    (coinMonsterDistance < coinDistance && monsterCoins >= me.coins / 2) ||
                    (coinMonsterDistance <= coinDistance && monsterCoins >= me.coins)
                ) {
                    coinCloserMonsters++;
                }
            }

            var coinMonsterFactor = (100 - ((100 / monstersCount) * coinCloserMonsters)) / 100;
            if (coinMonsterFactor < 1) coinMonsterFactor *= coinFactor;
            if (coinMonsterFactor >= 1) coinMonsterFactor *= 15;
            score += ((coinValue * coinMonsterFactor) / coinDistance) + (centerMonstersAvg === null || centerMonstersAvg > 1.75 ? -1 * (50 / coinDistanceCenter) : 200 / coinDistanceCenter);
        }

        return score + Math.random();
    };

    var possibleMoves = [{x: 0, y: 0, c: 'none'}];
    if (me.locationX > 0) possibleMoves.push({x: -1, y: 0, c: 'west'});
    if (me.locationY > 0) possibleMoves.push({x: -0, y: -1, c: 'north'});
    if (me.locationX < me.arenaLength - 1) possibleMoves.push({x: 1, y: 0, c: 'east'});
    if (me.locationY < me.arenaLength - 1) possibleMoves.push({x: 0, y: 1, c: 'south'});

    var topCommand, topScore = null;
    for (i = 0; i < possibleMoves.length; i++) {
        var score = getScore(me.locationX + possibleMoves[i].x, me.locationY + possibleMoves[i].y);
        if (topScore === null || score > topScore) {
            topScore = score;
            topCommand = possibleMoves[i].c;
        }
    }

    if (isApocalypse) botNotes.storeData('mode', mode);

    return topCommand;
}

Цей бот (він же "TBTPTGCBCBA") намагається прийняти найкраще можливе рішення, генеруючи бал за кожен можливий хід, і вибирає хід з вищим балом за кожен хід.

Система підрахунків балів має багато деталей, які розвиваються з початку виклику. Їх можна загалом описати так:

  • Чим ближче монети до можливого руху, тим більше балів отримує рух. Якщо на монеті немає інших можливих учасників, оцінка буде ще вище. Якщо на монеті є інші можливі учасники, оцінка знижується.
  • Якщо інший бот близький до можливого ходу і має менше монет, залежно від фази гри, це може означати більше балів за цей хід. Тому "TBTPTGCBCBA" випадково з'їдає декілька інших ботів у кожній грі.
  • Якщо інший бот близький до можливого ходу з рівними або кількома очками, цей хід отримує достатньо негативної оцінки, щоб уникнути смерті. Звичайно, можуть бути випадки, що всі можливі рухи погані і смерті не уникнути, але це дуже рідко.
  • Існує механізм відстеження кількості ботів посеред плати протягом останніх 20 оборотів. Якщо середній показник досить низький, всі рухи в бік монет у середині отримують більше балів, а якщо середнє значення високе, то всі рухи в бік монет у середині отримують нижчий бал. Цей механізм дозволяє уникнути конфліктів із «феодальною знаттю». Оскільки "феодальний дворянин" завжди знаходиться посередині (якщо його не переслідують), середня кількість ботів посередині зростає, а "TBTPTGCBCBA" розуміє уникати середини, якщо є кращий варіант поза середньої площі. Якщо "феодальний дворянин" помирає, середнє знижується, а "TBTPTGCBCBA" розуміє, що може використовувати середину.
  • Є деякі фактори, які динамічно змінюються залежно від фази гри (виявляється з числа живих ботів), ці фактори впливають на бал у кожному з вищезазначених пунктів.
  • Цей бот має особливі здібності. З часом він втомлюється від егоїзму «феодальної знаті» та утиску селян. У потрібний момент воно підніметься, щоб покласти край неприємній системі феодалізму. Успішна спроба не тільки допомагає бідним селянам, але й забезпечує більший шанс на виграш завдяки монетам, узятим у «феодальної знаті».

Здається, набагато розумніший за інших
Redwolf Programs

5
Мені подобається частина монстрів у парамах
програми Redwolf

9

Антикапіталіст | Javascript

Не має стимулу йти за монетами, але намагається розмістити себе рівно між двома найбагатшими ботами з однаковою сумою грошей, сподіваючись, вони полюють на нього і врешті-решт схоплять його одночасно, взявши з собою двох капіталістів, коли він помре . Не активно чинить опір отримання монет, тому він може стати більш соковитою мішенню.

function antiCapitalist(me, capitalists, coins){

    function acquireTargets(capitalists){
        capitalists.sort((a, b) => a[2] < b[2]);
        let previousCapitalist;
        for(let i in capitalists){
            let capitalist = capitalists[i];

            if(capitalist[2] === 0){
                return false;
            }
            if(previousCapitalist && capitalist[2] === previousCapitalist[2]){
                return [previousCapitalist, capitalist];
            }

            previousCapitalist = capitalist;
        }

        return false;
    }

    function move(){
        const targets = acquireTargets(capitalists);
        if(!targets){
            return 'none';
        }

        const coordinates = [Math.floor((targets[0][0] + targets[1][0]) / 2), Math.floor((targets[0][1] + targets[1][1]) / 2)];
        if(me.locationX !== coordinates[0]){
            return me.locationX < coordinates[0] ? 'east' : 'west';
        }
        else if(me.locationX !== coordinates[1]){
            return me.locationY < coordinates[1] ? 'south' : 'north';
        }
        else {
            return 'none';
        }
    }

    return move();
}

9

GUT, JavaScript

function gut(me, others, coins) {
    // Prepare values for the calculation
    var x = me.locationX;
    var y = me.locationY;
    var cMe = me.coins+1;
    var arenaLen = me.arenaLength;

    var objects = [];

    // Add bots to objects
    for (var i = 0; i < others.length; i++) {
        objects.push([others[i][0],others[i][1],others[i][2]/cMe]);
    }

    // Add coins to objects
    for (var j = 0; j < coins.length; j++) {
        var coinVal = 0;

        if (j == 0) {
            // Gold has a higher coin value
            coinVal = -10;
        } else {
            // Silver has a lower coin value
            coinVal = -5;
        }

        objects.push([coins[j][0],coins[j][1],coinVal/cMe]);
    }

    // Perform the calculation
    // x acceleration
    var x_acceleration = 0;

    for (var k=0; k < objects.length; k++) {
        var kval = objects[k][2];
        var xval = objects[k][0];

        x_acceleration += 200*kval/cMe*(x-xval)*Math.exp(Math.pow(kval,2)-50*Math.pow(x-xval,2));
    }

    // y acceleration
    var y_acceleration = 0;

    for (var l=0; l < objects.length; l++) {
        var kval = objects[l][2];
        var yval = objects[l][1];

        y_acceleration += 200*kval/cMe*(y-yval)*Math.exp(Math.pow(kval,2)-50*Math.pow(y-yval,2));
    }

    // Compare the values
    if (Math.abs(y_acceleration)>Math.abs(x_acceleration)) {
        if (y_acceleration < 0) {
            // Don't fall off the edge
            if (y>0) {
                return "north";
            } else {
                return "none";
            }
        } else {
            if (y<arenaLen-1) {
                return "south";
            } else {
                return "none";
            }
        }
    } else if (Math.abs(y_acceleration)<Math.abs(x_acceleration)) {
        if (x_acceleration < 0) {
            if (x>0) {
                return "west";
            } else {
                return "none";
            }
        } else {
            if (x<arenaLen-1) {
                return "east";
            } else {
                return "none";
            }
        }
    } else {
        return "none";
    }
}

З потенційно переможними у нас є два поля: поле бота та монети. Однак природа не така вже й складна. Настав час уніфікувати два поля для створення Великої єдиної теорії .

По-перше, нам потрібно опрацювати, який потенціал поля. Якщо припустити, що наш власний бот ніяк не впливає на поле, ми можемо записати це як:

V=nkn(ekn2100(xxn)2+ekn2100(yyn)2)

kn(xn,yn)

Відносна властивість об'єкта обчислюється так:

k=cobjectcme

ccme=cself+1cself

Назвемо цю корекційну частину модифікованою бетаніанової динамікою (MOBD) .

Кінетичну енергію ми також можемо знайти як:

T=12cme(x˙2+y˙2)

Тепер ми можемо розрахувати дію:

Action=ab(TV)dt=ab(12cme(x˙2+y˙2)nkn(ekn2100(xxn)2+ekn2100(yyn)2))dt

Отже, лагранжанин нашого бота в полі «монета-бот»:

L=12cme(x˙2+y˙2)nkn(ekn2100(xxn)2+ekn2100(yyn)2)

Тепер нам потрібно розв’язати рівняння Ейлера-Лагранжа:

ddtLx˙=Lx

і:

ddtLy˙=Ly

Тому:

ddtLx˙=ddt[cmex˙]=cmex¨

Lx=n200kn(xxn)ekn2100(xxn)2

x¨=n200kncme(xxn)ekn2100(xxn)2

І також:

ddtLy˙=ddt[cmey˙]=cmey¨

Ly=n200kn(yyn)ekn2100(yyn)2

y¨=n200kncme(yyn)ekn2100(yyn)2

Тепер нам не потрібно йти далі: ми просто дивимось на напрямок загального прискорення:

output={northif y¨<0 and |y¨|>|x¨|southif y¨>0 and |y¨|>|x¨|westif x¨<0 and |x¨|>|y¨|eastif x¨>0 and |x¨|>|y¨|noneif |y¨|=|x¨|

І просто так, ми об’єднали монети та боти. Де моя Нобелівська премія?


5
Вашу Нобелівську премію було втрачено на пошті, але ми можемо надати вам нагороду Еммі
програми Redwolf

1
Схоже, фізика починає набирати популярність у цьому виклику. :—D. І звичайно мені дуже цікаво, наскільки це буде добре.
Раміллі

1
(До речі, ви могли врятувати клопоту за рівняннями Ейлера-Лагранжа, тому що вони зводять до загальновідомого факту, що F = c_me a = - град U:
Раміллі

@Ramillies Meh, було веселіше робити це таким чином: D
Beta Decay

1
Ви впевнені, що хочете використовувати k = монети чогось іншого / ваші монети? Ви починаєте без монет ... і з NaN скрізь, ви не надто ймовірні, щоб отримати їх.
Раміллі

8

Золотанки, JavaScript (Node.js)

function goldilocks(me, others, coins) {
  let target = coins[0]; // Gold
  let x = target[0] - me.locationX;
  let y = target[1] - me.locationY;

  mymove = 'none'
  if (Math.abs(x) <= Math.abs(y) && x != 0)
    mymove = x < 0 ? 'west' : 'east'
  else if (y != 0)
    mymove = y < 0 ? 'north' : 'south'

  return mymove
}

Спробуйте в Інтернеті!

Просто замикається на місці золотої монети і щоразу рухається до неї. (Завдяки боту "B33-L1N3" @ Mayube для оригінального коду, який він використовував, хоча ледве будь-який з них залишається.)


Це досить приємний, простий бот. Мені це подобається.
Програми Redwolf

2
До речі, я використовую цього бота в якості тесту для свого контролера (:
Програми Redwolf

8

Алгоритм навчання третього роду | JavaScript (Node.js)

function run(me) {
	options = [];
	if (me.locationX > 0) options.push('west');
	if (me.locationY > 0) options.push('north');
	if (me.locationX < me.arenaLength) options.push('east');
	if (me.locationY < me.arenaLength) options.push('south');

	return options[Math.floor(Math.random() * options.length)];
}

Спробуйте в Інтернеті!

Після кількох поколінь навчання, цей бот дізнався, що залишати арену = погано


О добре. Я чув, що це називається "Природний відбір"
програми Redwolf

5
Де другий рід
Luis felipe De jesus Munoz

11
@LuisfelipeDejesusMunoz Він залишив арену.
Джо.

Це хороший бот для налагодження контролера
Redwolf Programs

3
О, до речі, арена починається з 0, так і має бути arenaLength - 1. Це вбило вашого бота справедливо кілька разів для багатьох
програми Redwolf

7

B33-L1N3 | JavaScript (Node.js)

function(me, others, coins) {
	// Do nothing if there aren't any coins
	if (coins.length == 0) return 'none';
	// Sort by distance using Pythagoras' Theorem
	coins = coins.sort((a, b) => (a[0] ** 2 + a[1] ** 2) - (b[0] ** 2 + b[1] ** 2));
	// Closest coin
	let target = coins[0];
	let x = target[0];
	let y = target[1];

	// Util function for movement
	function move(pos, type) {
		let moveTypes = { X: ['east', 'west'], Y: ['south', 'north'] };
		if (pos > me['location'+type]) return moveTypes[type][0];
		else return moveTypes[type][1];
	}

	// Move the shortest distance first
	if (x < y && x != me.locationX) return move(x, 'X');
	else if (y != me.locationY) return move(y, 'Y');
}

Спробуйте в Інтернеті!

Робить білайн для найближчої монети


О, я думав, що B33-L1N3 - якийсь номер моделі
програми Redwolf

+1 для імені
Каїн

let coins = ...Uncaught SyntaxError: Identifier 'coins' has already been declared
Ніч2

Видалитиlet
Програми Redwolf

5

Livin 'on the Edge, JavaScript

function LivinOnTheEdge (myself, others, coins) {
  x = myself.locationX;
  y = myself.locationY;
  xymax = myself.arenaLength - 1;
  if (x < xymax && y == 0) {
      return 'east';
    } else if (y < xymax && x == xymax) {
      return 'south';
    } else if (x > 0 && y == xymax) {
      return 'west';
  } else {
    return 'north';
  }
}

Цей, хто чув край арени, є небезпечним місцем. Не знаючи страху, він невтомно обводить дошку за годинниковою стрілкою, лише в сантиметрах від певної смерті, яка чекає за кордоном, сподіваючись, що жоден інший бот не наважиться просунутися так близько до краю краю.


1
Це не закінчилося б добре, якби був створений ще один бот, який мав ще 1 монету, і патрулював кордон у зворотному напрямку (:
Програми Redwolf

8
Я хотів би пожартувати прикордонний контроль, але я залишаю це до @BetaDecay
Programs

5

Пошкодження, JavaScript (Node.js)

function damacy(me, others, coin) {
  let xdist = t => Math.abs(t[0] - me.locationX)
  let ydist = t => Math.abs(t[1] - me.locationY)
  function distanceCompare(a, b, aWt, bWt) {
    aWt = aWt || 1
    bWt = bWt || 1
    return (xdist(a) + ydist(a)) / aWt - (xdist(b) + ydist(b)) / bWt
  }
  function hasThreat(loc) {
    let threat = others.filter(b => b[0] == loc[0] && b[1] == loc[1] && b[2] >= me.coins)
    return (threat.length > 0)
  }
  function inArena(loc) {  // probably unnecessary for this bot
    return loc[0] >= 0 && loc[1] >= 0 && loc[0] < me.arenaLength && loc[1] < me.arenaLength
  }
  function sortedCoins() {
    coinsWithValues = coin.map((coords, i) => coords.concat((i == 0) ? 5 : 2))
    coinsWithValues.sort((a, b) => distanceCompare(a, b, a[2], b[2]))
    return coinsWithValues.map(c => c.slice(0, 2))
  }
  othersPrev = botNotes.getData('kata_others_pos')
  botNotes.storeData('kata_others_pos', others)
  if (othersPrev) {

    for(let i = 0; i < others.length; i++) {
      let bot = others[i]

      let matchingBots = othersPrev.filter(function (b) {
        let diff = Math.abs(b[0] - bot[0]) + Math.abs(b[1] - bot[1])
        if (diff >= 2)
          return false // bot can't have jumped
        return [0, 2, 5].includes(bot[2] - b[2])
      })

      if (matchingBots.length > 0) {
        let botPrev = matchingBots.shift()
        // remove matched bot so it doesn't get matched again later
        othersPrev = othersPrev.filter(b => b[0] != botPrev[0] || b[1] != botPrev[1])
        bot[0] = Math.min(Math.max(bot[0] + bot[0] - botPrev[0], 0), me.arenaLength-1)
        bot[1] = Math.min(Math.max(bot[1] + bot[1] - botPrev[1], 0), me.arenaLength-1)
      }
    }
  }

  let eatables = others.filter(b => b[2] < me.coins && b[2] > 0)
  let targets
  if (eatables.length > 0) {
    targets = eatables.sort(distanceCompare)
  }
  else {
    targets = sortedCoins()
  }

  let done, newLoc, dir
  while (!done && targets.length > 0) {
    t = targets.shift()
    if ((xdist(t) <= ydist(t) || ydist(t) == 0) && xdist(t) != 0) {
      let xmove = Math.sign(t[0] - me.locationX)
      dir = xmove < 0 ? 'west' : 'east'
      newLoc = [me.locationX + xmove, me.locationY]
      if (!hasThreat(newLoc) && inArena(newLoc))
        done = 1
    }

    if (!done) {
      let ymove = Math.sign(t[1] - me.locationY)
      dir = ['north', 'none', 'south'][ymove + 1]
      newLoc = [me.locationX, me.locationY + ymove]
      if (!hasThreat(newLoc) && inArena(newLoc))
        done = 1
    }
  }

  if (!done)
    dir = 'none'


  return dir
}

Спробуйте в Інтернеті!

Один останній бот на основі катамарі на сьогодні, цього разу з небагато пам’яті. Завдяки @BetaDecay за пропозицію імені - безумовно, кумедніше ім’я, ніж моє simplePredictorKatamari.

Намагається розібратися, як боти рухалися в останню чергу, і, виходячи з цього, прогнозує, куди вони спробують рухатись наприкінці цього повороту (якщо припустити, що вони продовжуватимуть рухатися в тому ж напрямку).

(Завдяки @ fəˈnɛtɪk, за те, що я помітив, що я називав неправильне ім’я функції у botNotes та @ OMᗺ за те, що помітив помилку в базовому коді.)


Це, мабуть, єдиний зараз, який може зловити інших поза тим, що просто пощастить.
Каїн

Чи не слід вважати, що боттони "зберігаються" не задані?
fəˈnɛtɪk

@ fəˈnɛtɪk Дивіться, вже потрібна помилка! :) Дякую, виправлено зараз.
sundar

Ви повинні замінити aWt = 1в парамах на aWtі поставити aWt = aWt || 1під ним (Те саме bWt). Це запобігає помилкам.
Програми Redwolf

5

Протон | JavaScript

Proton=(myself,others,coins)=>{
  x=myself.locationX;
  y=myself.locationY;
  power=myself.coins;
  arenaSize=myself.arenaLength;
  forceX=0;
  forceY=0;
  prevState=botNotes.getData("proton_velocity");
  if(prevState){
    velocity=prevState[0];
    direction=prevState[1];
  }
  else{
    velocity=0;
    direction=0;
  }
  for(i=0;i<coins.length;i++){
    if(Math.abs(x-coins[i][0])+Math.abs(y-coins[i][1])==1){
      velocity=0;
      direction=0;
      botNotes.storeData("proton_velocity",[velocity,direction]);
      if(x-coins[i][0]==1){return "west";}
      if(coins[i][0]-x==1){return "east";}
      if(y-coins[i][1]==1){return "north";}
      if(coins[i][1]-y==1){return "south";}
    }
    else{
      dist=Math.sqrt(Math.pow(x-coins[i][0],2)+Math.pow(y-coins[i][1],2));
      if(i==0){
        forceX+=(x-coins[i][0])*5/Math.pow(dist,3);
        forceY+=(y-coins[i][1])*5/Math.pow(dist,3);
      }
      else{
        forceX+=(x-coins[i][0])*2/Math.pow(dist,3);
        forceY+=(y-coins[i][1])*2/Math.pow(dist,3);
      }
    }
  }
  for(i=0;i<others.length;i++){
    if(Math.abs(x-others[i][0])+Math.abs(y-others[i][1])==1&&power>others[i][2]){
      velocity=0;
      direction=0;
      botNotes.storeData("proton_velocity",[velocity,direction]);
      if(x-others[i][0]==1){return "west";}
      if(others[i][0]-x==1){return "east";}
      if(y-others[i][1]==1){return "north";}
      if(others[i][1]-y==1){return "south";}
    }
    else{
      dist=Math.sqrt(Math.pow(x-others[i][0],2)+Math.pow(y-others[i][1],2));
      forceX+=(x-others[i][0])*others[i][2]/Math.pow(dist,3);
      forceY+=(y-others[i][1])*others[i][2]/Math.pow(dist,3);
    }
  }
  vX=velocity*Math.cos(direction)+10*forceX/Math.max(1,power);
  vY=velocity*Math.sin(direction)+10*forceY/Math.max(1,power);
  velocity=Math.sqrt(vX*vX+vY*vY);
  if(velocity==0){return "none"}
  retval="none";
  if(Math.abs(vX)>Math.abs(vY)){
    if(vX>0){
      if(x<arenaSize-1){retval="east";}
      else{vX=-vX;retval="west";}
    }
    else{
      if(x>0){retval="west";}
      else{vX=-vX;retval="east";}
    }
  }
  else{
    if(vY>0){
      if(y<arenaSize-1){retval="south";}
      else{vY=-vY;retval="north";}
    }
    else{
      if(y>0){retval="north";}
      else{vY=-vY;retval="south";}
    }
  }
  direction=Math.atan2(-vY,vX);
  botNotes.storeData("proton_velocity",[velocity,direction]);
  return retval;
}

Всі монети (включаючи ті, що їх тримають інші боти) випромінюють силу до Protonbot. Виходячи з цієї сили, вона нарощує швидкість і відскакує від стін (одразу обертається, потрапляючи на межу). Якщо він опиняється поруч з ботом або монетою, яку він може споживати, Сильна ядерна сила бере на себе і вона рухається до споживання, скидаючи всю швидкість, коли це робить.


Гм, ядерна фізика застосовується для пошуку скарбів? Це перемагає науковий канал будь-якого дня!
Програми Redwolf

Вам потрібно замінити sinна Math.sin, cosз Math.cos, і так далі
Програми Redwolf

4

Не так сліпо | JavaScript (Node.js)

Важлива примітка: Цей підхід не є повністю моїм, і на нього було дано відповідь у подібному питанні . Не забудьте проголосувати і за цю відповідь.

Ви коли-небудь чули про алгоритм A * просування маршрутів? ось. Він створює найкращий шлях від однієї точки до менш цінної монети (оскільки всі йдуть за найціннішою, ніхто не збирається за меншу) і намагається не зіткнутися з будь-яким іншим користувачем.

Очікує наступних параметрів:

AI({locationX: 3, locationY: 1, arenaLength: [5,5]}, [[2,1],[2,2], ...],[[1,2],[3,1], ...])

Можливо, я роблю одну, яка йде на полювання на інших ботів


function AI(me, others, coins){
    var h = (a,b) => Math.abs(a[0] -b[0]) + Math.abs(a[1] -b[1])
    var s = JSON.stringify;
    var p = JSON.parse;
    var walls = others.slice(0,2).map(s);
    var start = [me.locationX, me.locationY];
    var goal = coins.pop();
    var is_closed = {};
    is_closed[s(start)] = 0;
    var open = [s(start)];
    var came_from = {};
    var gs = {};
    gs[s(start)] = 0;
    var fs = {};
    fs[s(start)] = h(start, goal);
    var cur;
    while (open.length) {
        var best;
        var bestf = Infinity;
        for (var i = 0; i < open.length; ++i) {
            if (fs[open[i]] < bestf) {
                bestf = fs[open[i]];
                best = i;
            }
        }
        cur = p(open.splice(best, 1)[0]);
        is_closed[s(cur)] = 1;
        if (s(cur) == s(goal)) break;
        for (var d of [[0, 1], [0, -1], [1, 0], [-1, 0]]) {
            var next = [cur[0] + d[0], cur[1] + d[1]];
            if (next[0] < 0 || next[0] >= me.arenaLength[0] ||
                next[1] < 0 || next[1] >= me.arenaLength[1]) {
                continue;
            }
            if (is_closed[s(next)]) continue;
            if (open.indexOf(s(next)) == -1) open.push(s(next));
            var is_wall = walls.indexOf(s(next)) > -1;
            var g = gs[s(cur)] + 1 + 10000 * is_wall;
            if (gs[s(next)] != undefined && g > gs[s(next)]) continue;
            came_from[s(next)] = cur;
            gs[s(next)] = g;
            fs[s(next)] = g + h(next, goal);
        }
    }
    var path = [cur];
    while (came_from[s(cur)] != undefined) {
        cur = came_from[s(cur)];
        path.push(cur);
    }
    var c = path[path.length - 1];
    var n = path[path.length - 2];
    if(n){
        if (n[0] < c[0]) {
            return "west";
        } else if (n[0] > c[0]) {
            return "east";
        } else if (n[1] < c[1]) {
            return "north";
        } else {
            return "south";
        }
    }else{
        return "none";
    }
}

1
Нічого ... вже алгоритм накладання маршрутів? Минуло лише 3 години!
Програми Redwolf

@RedwolfPrograms Як я вже говорив, це скопійовано з іншого подібного завдання. Просто потрібно було адаптувати його до цього.
Luis felipe De jesus Munoz

Мої алгоритми стосуються тих монет, які є найбезпечнішими.
fəˈnɛtɪk

4

Трус | Пітон 2

import random

def move(me, others, coins):
    target = (me.locationX, me.locationY)

    # Identify the dangerous opponents.
    threats = [i for i, value in enumerate(others[2]) if value >= me.coins]

    # If no one scary is nearby, find a nearby coin.
    safe = True
    for x, y in self.coins:
        distance = abs(me.locationX - x) + abs(me.locationY - y)
        safe = True
        for i in threats:
            if abs(others[0][i] - x) + abs(others[1][i] - y) <= distance:
                safe = False
                break

        if safe:
            target = (x, y)
            break

    # Otherwise, just try not to die.
    if not safe:
        certain = []
        possible = []
        for x, y in [
            (me.locationX, me.locationY),
            (me.locationX + 1, me.locationY),
            (me.locationX - 1, me.locationY),
            (me.locationX, me.locationY + 1),
            (me.locationX, me.locationY - 1),
        ]:
            # Don't jump off the board.
            if x < 0 or y < 0 or x == me.arenaLength or y == me.arenaLength:
                continue

            # Check if we can get away safely.
            for i in threats:
                if abs(others[0][i] - x) + abs(others[1][i] - y) <= 1:
                    break
            else:
                certain.append((x, y))

            # Check if we can take a spot someone is leaving.
            for i in threats:
                if others[0][i] = x and others[1][i] == y:
                    for i in threats:
                        if abs(others[0][i] - x) + abs(others[1][i] - y) == 1:
                            break
                    else:
                        possible.append((x, y))

        if certain:
            target = random.choice(certain)
        elif possible:
            target = random.choice(possible)
        # Otherwise, we're doomed, so stay still and pray.

    directions = []
    x, y = target
    if x < me.locationX:
        directions.append('west')
    if x > me.locationX:
        directions.append('east')
    if y < me.locationY:
        directions.append('north')
    if y > me.locationY:
        directions.append('south')
    if not directions:
        directions.append('none')

    return random.choice(directions)

Уникайте ботів з більшою кількістю грошей, якщо це можливо. В іншому випадку візьміть гроші, які лежать навколо.


Це найосновніший бот, який має шанс на перемогу
Redwolf Programs

4

Бот для погони за дикими гусками, Javascript

Бот, який дуже добре ухиляється від інших ботів, але дуже погано отримує монети.


Алгоритм:

  1. Якщо сусідніх ботів немає, не повертайте жодних
  2. Інакше:
    1. Не повертайте жодного з випадковим шансом 1/500 шансу (це призначено для запобігання застоям).
    2. Визначте, до яких просторів можна переміщатись (тобто всередині арени, а не займає інший бот)
    3. Поверніть один навмання

Код:

function wildGooseChase(me, others, coins){
    x = me.locationX;
    y = me.locationY;

    dirs = {};
    dirs[(x+1)+" "+y] = "east";
    dirs[(x-1)+" "+y] = "west";
    dirs[x+" "+(y+1)] = "south";
    dirs[x+" "+(y-1)] = "north";

    mov = {};
    mov["east"] = [x+1,y];
    mov["west"] = [x-1,y];
    mov["north"] = [x,y-1];
    mov["south"] = [x,y+1]; 

    possibleDirs = ["east","west","north","south"];

    for (i = 0; i < others.length; i++){
        if (others[i][0]+" "+others[i][1] in dirs){
            possibleDirs.splice(possibleDirs.indexOf(dirs[others[i][0]+" "+others[i][1]]),1);
        }
    }

    if (possibleDirs.length == 4 || Math.floor(Math.random() * 500) == 0){
        return "none"
    }

    for (i = 0; i < possibleDirs.length; i++){
        if (mov[possibleDirs[i]][0] == me.arenaLength || mov[possibleDirs[i]][0] < 0 
        || mov[possibleDirs[i]][1] == me.arenaLength || mov[possibleDirs[i]][1] < 0){
            var index = possibleDirs.indexOf(possibleDirs[i]);
            if (index != -1) {
                possibleDirs.splice(index, 1);
                i--;
            }
        }
    }

    if (possibleDirs.length == 0){
         return "none";
    }

    return possibleDirs[Math.floor(Math.random() * possibleDirs.length)];
}

Спробуйте в Інтернеті!

Примітка до програм Redwolf:

Цей бот може викликати дуже довгі раунди. Я взяв деякі свободи, щоб запобігти застоям, але не перевіряв, чи справді вони ефективні. Якщо під час тестування цей бот стає проблемою, будь ласка, нехай його дискваліфікують.


Дякую за замітку. Експерт ухиляється від шансу зібрати достатньо монет під час переслідування
Redwolf Programs

Мені подобається це. Це майже як принада для мисливських роботів
Beta Decay

4

KatamariWithValues, JavaScript (Node.js) ,

function katamariWithValues(me, others, coin) {
  let xdist = t => Math.abs(t[0] - me.locationX)
  let ydist = t => Math.abs(t[1] - me.locationY)
  function distanceCompare(a, b, aWt = 1, bWt = 1) {
    return (xdist(a) + ydist(a)) / aWt - (xdist(b) + ydist(b)) / bWt
  }
  function hasThreat(loc) {
    let threat = others.filter(b => b[0] == loc[0] && b[1] == loc[1] && b[2] >= me.coins)
    return (threat.length > 0)
  }
  function inArena(loc) {  // probably unnecessary for this bot
    return loc[0] >= 0 && loc[1] >= 0 && loc[0] < me.arenaLength && loc[1] < me.arenaLength
  }
  function sortedCoins() {
    coinsWithValues = coin.map((coords, i) => coords.concat((i == 0) ? 5 : 2))
    coinsWithValues.sort((a, b) => distanceCompare(a, b, a[2], b[2]))
    return coinsWithValues.map(c => c.slice(0, 2))
  }

  let eatables = others.filter(b => b[2] < me.coins && b[2] > 0)
  let targets
  if (eatables.length > 0) {
    targets = eatables.sort(distanceCompare)
  }
  else {
    targets = sortedCoins()
  }

  let done, newLoc, dir
  while (!done && targets.length > 0) {
    t = targets.shift()
    if ((xdist(t) <= ydist(t) || ydist(t) == 0) && xdist(t) != 0) {
      let xmove = Math.sign(t[0] - me.locationX)
      dir = xmove < 0 ? 'west' : 'east'
      newLoc = [me.locationX + xmove, me.locationY]
      if (!hasThreat(newLoc) && inArena(newLoc))
        done = 1
    }

    if (!done) {
      let ymove = Math.sign(t[1] - me.locationY)
      dir = ['north', 'none', 'south'][ymove + 1]
      newLoc = [me.locationX, me.locationY + ymove]
      if (!hasThreat(newLoc) && inArena(newLoc))
        done = 1
    }
  }

  if (!done)
    dir = 'none'

  return dir
}

Спробуйте в Інтернеті!

(Дякуємо @ OMᗺ за те, що вказав на помилку в оригінальному коді, на якому ґрунтувався.)

Намагається рости, "поїдаючи" ботів з меншою кількістю монет, ніж сама. Якщо це неможливо (такого бота немає), то шукає найближчу монету.

Ця версія має невеликі зміни, щоб (а) надавати більше переваг золотим монетам, ніж срібним монетам - з ризиком того, що пошук більш віддалених золотих монет може призвести до вартості життя бота або призведе до переслідування за золотом дурня (б) пропустити ботів з 0 монет - не потрібно витрачати час на переслідування за ними.


Розумний мисливець ... ну, це навіть краще!
Програми Redwolf

@RedwolfPrograms Будемо сподіватися! :)
sundar

Потрібно було назвати це пошкодження;)
бета-розпад


4

Ввічливий недалекоглядний п’яний бот | JavaScript

function politeNearSightedDrunkBot(me, others, coins) {
  let directions = ['none','east','south','west','north']
  let drunkennessCoefficient = .2
  let nearSightedness = me.arenaLength - others.length + 2
  //drawCircle(me.locationX, me.locationY, nearSightedness*squareSize)

  function randomInt(a) {
    return Math.floor(Math.random() * a);
  }
  function getRandomDirection() {
    return ['east', 'west', 'north', 'south'][randomInt(4)]
  }

  function distanceTo(a) {
    return (Math.abs(a[0] - me.locationX) + Math.abs(a[1] - me.locationY))
  }
  function distanceBetween(a, b){
    return (Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]))
  }
  function isTargetSafe(a) {
    for (let i = 0; i < others.length; i++) {
      if (others[i][2] >= me.coins && distanceBetween(a, others[i]) <= distanceTo(a)) {
        return false //unnecessary loop, but I don't want to split out into a function
      }
    }
    return true
  }
  function amISafe() {
    for (let i = 0; i < others.length; i++) {
      if (others[i][2] >= me.coins && distanceTo(others[i]) == 1) {
        /*let num = botNotes.getData('turnsSpentAdjacentToEnemy')
        if (!num) {
          console.log('politeNearSightedDrunkBot: Woops!')
          botNotes.storeData('turnsSpentAdjacentToEnemy', 1)
        } else if (num == 1) {
          console.log('politeNearSightedDrunkBot: \'Scuse me...')
          botNotes.storeData('turnsSpentAdjacentToEnemy', 2)
        } else if (num == 2) {
          console.log('politeNearSightedDrunkBot: D\'ye mind?')
          botNotes.storeData('turnsSpentAdjacentToEnemy', 3)
        } else if (num == 3) {
          console.log('politeNearSightedDrunkBot: Bugger off!')
        }*/
        return false
      }
    }
    return true
  }
  function getSafeDirections() {
    let candidates = {'none': true, 'east': true, 'south': true, 'west': true, 'north': true}
    if (me.locationY == 0) {
      candidates['north'] = false
    } else if (me.locationY == me.arenaLength - 1) {
      candidates['south'] = false
    }
    if (me.locationX == 0) {
      candidates['west'] = false
    } else if (me.locationX == me.arenaLength - 1) {
      candidates['east'] = false
    }
    if (!amISafe()) {
      candidates['none'] = false
    }/* else {
      botNotes.storeData('turnsSpentAdjacentToEnemy', 0)
    }*/
    if (candidates['north'] && !isTargetSafe([me.locationX, me.locationY-1])) {
      candidates['north'] = false
    }
    if (candidates['south'] && !isTargetSafe([me.locationX, me.locationY+1])) {
      candidates['south'] = false
    }
    if (candidates['west'] && !isTargetSafe([me.locationX-1, me.locationY])) {
      candidates['west'] = false
    }
    if (candidates['east'] && !isTargetSafe([me.locationX+1, me.locationY])) {
      candidates['east'] = false
    }
    if (candidates['none']) {
    }
    return candidates
  }
  function getSafeCoins() {
    let safestCoins = []
    let coinSizes = [5, 2, 2, 2, 2]
    for (let i = 0; i < coins.length; i++) {
      let distanceToThisCoin = distanceTo(coins[i])
      if (distanceToThisCoin < nearSightedness && isTargetSafe(coins[i])) {
        safestCoins.push([coins[i][0], coins[i][1], coinSizes[i], distanceToThisCoin])
        //alert('Coin at (' + coins[i][0] + ', ' + coins[i][1] + ') is safe!')
      }
    }
    if (safestCoins.length == 0) {
      //alert('No safe coins!')
    }
    return safestCoins
  }

  function getAdditiveBestDirectionToTargets(targets) {
    let candidates = {'east': 0, 'south': 0, 'west': 0, 'north': 0}
    for (let i = 0; i < targets.length; i++) {
      if (targets[i][0] < me.locationX) { 
        candidates['west'] = candidates['west'] + targets[i][2]/targets[i][3]
      } else if (targets[i][0] > me.locationX) {
        candidates['east'] = candidates['east'] + targets[i][2]/targets[i][3]
      }
      if (targets[i][1] > me.locationY) { 
        candidates['south'] = candidates['south'] + targets[i][2]/targets[i][3]
      } else if (targets[i][1] < me.locationY) {
        candidates['north'] = candidates['north'] + targets[i][2]/targets[i][3]
      }
    }
    for (let key in candidates) {
      //alert(key + ': ' + candidates[key])
    }
    return candidates
  }

    let targetCoins = getSafeCoins()
    let safeDirections = getSafeDirections()
    let chosenDir = null
    if (targetCoins.length > 0) {
      //alert('Coins found! Exactly ' + targetCoins.length)
      let weightedDirections = getAdditiveBestDirectionToTargets(targetCoins)
      let bestOptionWeight = 0
      let choices = []
      for (let key in safeDirections) {
        if (safeDirections[key] && key != 'none') {
          if (weightedDirections[key] == bestOptionWeight) {
            choices.push(key)
          } else if (weightedDirections[key] > bestOptionWeight) {
            choices = [key]
            bestOptionWeight = weightedDirections[key]
          }
        }
      }
      if (choices.length > 0) {
        //alert('Picking from choices, ' + choices.length + ' options and best weight is ' + bestOptionWeight)
        chosenDir = choices[randomInt(choices.length)]
      } else {
        //alert('No safe choices!')
      }
    } else {
      let lastDir = botNotes.getData('direction') || 'none'
      if (safeDirections[lastDir] && Math.random() >= drunkennessCoefficient) {
        chosenDir = lastDir
      }
    }

    if (!chosenDir) {
      //alert('indecisive!')
      let choices = []
      for (key in safeDirections) {
        if (safeDirections[key]) {
          choices.push(key)
        }
      }
      if (choices.length > 0) {
        chosenDir = choices[randomInt(choices.length)]
      } else {
        chosenDir = getRandomDirection()
      }
    }

    botNotes.storeData('direction', chosenDir)
    //alert('Moving ' + chosenDir)
    return chosenDir
}

Похитується навколо збирання монет поблизу, але випадково перемикає вказівки так часто. Робить те, що може, щоб не натрапити на когось, але він стає ... войовничим ... при загостренні. Як правило, тверезить, коли змагання тривають.

Можливо, знадобиться деяка налагодження, коли контролер повністю готовий, я працюю над цим.


3
Гм, вона піднімає планку, потім напивається на ній
Redwolf Programs

4

Зважений рух | JavaScript

WeightedMotion=(myself,others,coins)=>{
  x=myself.locationX;
  y=myself.locationY;
  power=myself.coins;
  arenaSize=myself.arenaLength;
  dirX=0;
  dirY=0;
  for(i=0;i<coins.length;i++){
    if(i==0){
      dirX+=5/(x-coins[i][0]);
      dirY+=5/(y-coins[i][1]);
    }
    else{
      dirX+=2/(x-coins[i][0]);
      dirY+=2/(y-coins[i][1]);
    }
  }
  for(i=0; i<others.length;i++){
    dirX+=(power-others[i][2])/(2*(x-others[i][0]));
    dirY+=(power-others[i][2])/(2*(y-others[i][1]));
  }
  if(Math.abs(dirX)>Math.abs(dirY)){
    if(dirX>0){
      if(x>0){return "west";}
      else{
        if(dirY>0){if(y>0)return "north";}
        else if(dirY<0){if(y<arenaSize-1)return "south";}
      }
    }
    else if(x<arenaSize-1){return "east";}
    else{
      if(dirY>0){if(y>0)return "north";}
      else if(dirY<0){if(y<arenaSize-1)return "south";}
    }
  }
  else{
    if(dirY>0){
      if(y>0){return "north";}
      else{
        if(dirX>0){if(x>0)return "west";}
        else if(dirX<0){if(x<arenaSize-1)return "east";}
      }
    }
    else if(y<arenaSize-1){return "south";}
    else{
      if(dirX>0){if(x>0)return "west";}
      else if(dirX<0){if(x<arenaSize-1){return "east";}
    }
  }
  return "none";
}

Рухається в напрямку, якому він призначив найбільше значення, уникаючи бігу по краю дошки.

Значення обчислюється як таке:

  • Монета = потужність монети / відстань до монети
  • Bot = Різниця в силі ботів / 2 * відстань до бота

1
Ну, це виглядає як досить дивовижний бот. Обов'язково перевірте напрямки, так як це буде реальна втратою , якщо ваш бот був майстер працює далеко від монет (:
Redwolf програми

Ну все ж. Я повинен бути хорошим, правда?
Програми Redwolf

Ну, опублікуй! Він доповнить менші, швидші боти, які також існують на даний момент у великих кількостях.
Програми Redwolf

for(i=0;i<6;i++){всього 5 монет, 1 золота та 4 срібних. Ваш цикл працює 6 разів з 0 до 5.
Ніч2,

3

Сліпий | JavaScript (Node.js)

Це безумовно не буде вигравати, але принаймні брати участь. Спершу спробуйте KoH challenge. Він сортує монети і переходить до найближчої. Він не шукає гравців, тому йому не байдуже, чи стикається він з іншими.

function(myself, others, coins){
    mx = myself.locationX
    my = myself.locationY
    l="west"
    r="east"
    u="north"
    d="south"
    n="none"

    if(coins.length == 0)
        return n

    var closestCoin = coins.sort(a=>Math.sqrt(Math.pow(mx-a[0],2) + Math.pow(my-a[1],2))).pop()
    cx = closestCoin[0]
    cy = closestCoin[1]

    return mx>cx?l:mx<cx?r:my>cy?u:my<cy?d:n
}

Хм, це може спрацювати, оскільки інші боти шукатимуть золото в першу чергу, потенційно залишаючи вас отримати срібло без жодних боїв
Redwolf Programs

3

Феодальна знать | JavaScript

Бажаний колір: #268299

function (noble, peasants, coins) {
    var center = (noble.arenaLength - 1) / 2, centerSize = noble.arenaLength / 4, peasantsCount = peasants.length,
        centerMin = center - centerSize, centerMax = center + centerSize, apocalypse = 2e4 - ((noble.arenaLength * 2) + 20), inDanger = false;

    var round = botNotes.getData('round');
    if (round === null || !round) round = 0;
    round++;
    botNotes.storeData('round', round);

    var getDistance = function (x1, y1, x2, y2) {
        return (Math.abs(x1 - x2) + Math.abs(y1 - y2)) + 1;
    };

    var isAtCenter = function (x, y) {
        return (x > centerMin && x < centerMax && y > centerMin && y < centerMax);
    };

    var getScore = function (x, y) {
        var score = 0, i, centerFactor = 10;

        for (i = 0; i < peasantsCount; i++) {
            var peasantCoins = peasants[i][2], peasantDistance = getDistance(x, y, peasants[i][0], peasants[i][1]);

            if (noble.coins > peasantCoins && isAtCenter(x, y)) {
                score += Math.min(100, peasantCoins) / peasantDistance;
            } else if (noble.coins <= peasantCoins && peasantDistance <= 3) {
                score -= (peasantDistance === 3 ? 50 : 2000);
                inDanger = true;
            }
        }

        for (i = 0; i < coins.length; i++) {
            if (isAtCenter(coins[i][0], coins[i][1])) {
                var coinDistance = getDistance(x, y, coins[i][0], coins[i][1]),
                    coinValue = (i === 0 ? 500 : 200),
                    coinCloserPeasants = 1;

                for (var j = 0; j < peasantsCount; j++) {
                    var coinPeasantDistance = getDistance(peasants[j][0], peasants[j][1], coins[i][0], coins[i][1]);
                    if (coinPeasantDistance <= coinDistance && peasants[j][2] >= noble.coins) coinCloserPeasants++;
                }

                score += (coinValue / coinCloserPeasants) / (coinDistance / 3);
            }
        }

        if (round >= apocalypse) centerFactor = 1000;
        score -= getDistance(x, y, center, center) * centerFactor;

        return score;
    };

    var possibleMoves = [{x: 0, y: 0, c: 'none'}];
    if (noble.locationX > 0) possibleMoves.push({x: -1, y: 0, c: 'west'});
    if (noble.locationY > 0) possibleMoves.push({x: -0, y: -1, c: 'north'});
    if (noble.locationX < noble.arenaLength - 1) possibleMoves.push({x: 1, y: 0, c: 'east'});
    if (noble.locationY < noble.arenaLength - 1) possibleMoves.push({x: 0, y: 1, c: 'south'});

    var topCommand, topScore = null;
    for (var i = 0; i < possibleMoves.length; i++) {
        var score = getScore(noble.locationX + possibleMoves[i].x, noble.locationY + possibleMoves[i].y);
        if (topScore === null || score > topScore) {
            topScore = score;
            topCommand = possibleMoves[i].c;
        }
    }

    if (round >= apocalypse) {
        var dg = botNotes.getData('dg');
        if (dg === null || !dg) dg = [];
        if (dg.length >= 20) dg.shift();
        dg.push(inDanger);
        botNotes.storeData('dg', dg);
        if (dg.length >= 20) {
            var itsTime = true;
            for (i = 0; i < dg.length; i++) if (!dg[i]) itsTime = false;
            if (itsTime) return 'none';
        }
    }

    return topCommand;
}

Цей феодальний дворянин залишається в центрі поля і претендує на нього як на власний палац. Збирає що-небудь у центрі для себе, але все, що в далеких господарствах, мусить принести йому селяни. Звичайно, якщо в палаці з’явиться розлючений могутній селянин, благородний може втекти, щоб врятувати своє життя, але він повертається, як тільки це стане в безпеці!

З плином часу селяни стають все сильнішими та сильнішими. Професійні бійці та потужні герої починають підніматися із селянства. Влада шляхетних постійно занепадає. Він намагається зберегти своє багатство та свою систему феодалізму разом, доки може. Але нарешті настає час, що він повинен прийняти свою віру, він повинен прийняти, що люди вже не хочуть феодалізму. Того дня феодальний дворянин відмовляється від усього, більше не втікає від могутніх селян і вбивається одним з них.


2

Квантовий гнат бот | JavaScript

function quantumGnatBot(me, others, coins) {
  let quantumCoefficient = .2
  let turn = botNotes.getData('turn')
  botNotes.storeData('turn', turn+1)
  botNotes.storeData('test', [2, 5, 7])
  botNotes.getData('test')
  let dG = {'none': [0, 0, -2, -2], 'east': [1, 0, me.arenaLength-1, -2], 'south': [0, 1, -2, me.arenaLength-1], 'west': [-1, 0, 0, -2], 'north': [0, -1, -2, 0]}

  function randomInt(a) {
    return Math.floor(Math.random() * a);
  }
  function getRandomDirection() {
    return ['east', 'west', 'north', 'south'][randomInt(4)]
  }
  function distanceBetween(a, b){
    return (Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]))
  }
  function isTargetSafe(a) {
    for (let i = 0; i < others.length; i++) {
      if (others[i][2] >= me.coins && distanceBetween(a, others[i]) <= 1) {
        return false
      }
    }
    return true
  }
  function isEnemySquare(a) {
    for (let i = 0; i < others.length; i++) {
      if (distanceBetween(a, others[i]) == 0) {
        return true
      }
    }
    return false
  }
  function getSafeDirections() {
    let candidates = {'none': true, 'east': true, 'south': true, 'west': true, 'north': true}
    for (let key in dG) {
      if (me.locationX == dG[key][2] || me.locationY == dG[key][3] || !isTargetSafe([me.locationX+dG[key][0], me.locationY+dG[key][1]])) {
        candidates[key] = false
      }
    }
    //alert('Safe: ' + candidates['north'] + ', ' + candidates['east'] + ', ' + candidates['south'] + ', ' + candidates['west'])
    return candidates
  }
  function getThreatDirections() {
    let candidates = {'none': false, 'east': false, 'south': false, 'west': false, 'north': false}
    for (let key in dG) {
      if (isEnemySquare([me.locationX+dG[key][0], me.locationY+dG[key][1]])) {
        candidates[key] = true
      }
    }
    return candidates
  }
  function getTargetDirections() {
    let targetBot = null
    let candidates = {'none': false, 'east': false, 'south': false, 'west': false, 'north': false}
    for (let i = 0; i < others.length; i++) {
      if (distanceBetween([me.locationX, me.locationY], others[i]) > 2 && (!targetBot || targetBot[2] < others[i][2])) {
        targetBot = others[i]
      }
    }
    if (targetBot[0] < me.locationX) {
      candidates['west'] = true
    } else if (targetBot[0] > me.locationX) {
      candidates['east'] = true
    }
    if (targetBot[1] > me.locationY) {
      candidates['south'] = true
    } else if (targetBot[1] < me.locationY) {
      candidates['north'] = true
    } 
    //alert('Chasing ' + targetBot[0] + ', ' + targetBot[1] + ' (' + targetBot[2] + ')')
    //alert('Path: ' + candidates['north'] + ', ' + candidates['east'] + ', ' + candidates['south'] + ', ' + candidates['west'])
    return candidates
  }

  let safeDirections = getSafeDirections()
  let threatDirections = getThreatDirections()
  let targetDirections = getTargetDirections()
  let chosenDir = null
  let choices = []
  for (key in safeDirections) {
    if (safeDirections[key] && targetDirections[key]) {
      choices.push(key)
    }
  }
  if (choices.length == 0) {
    //alert('Best options are blocked...')
    for (key in safeDirections) {
      if (safeDirections[key]) {
        choices.push(key)
      }
    }
  }
  for (key in threatDirections) {
    if (threatDirections[key] && Math.random() < quantumCoefficient) {
      //alert('Chance for quantum swap!')
      choices.push(key)
    }
  }
  if (choices.length > 0) {
    chosenDir = choices[randomInt(choices.length)]
  } else {
    //alert('No options? Guess we spin the wheel.')
    chosenDir = getRandomDirection()
  }

  return chosenDir
}

Цей дратівливий бот намагається гуляти навколо найсильнішого бота, не забиваючись, і має невеликий шанс поетапно перейти через тих, хто намагається полювати на нього. Він має тенденцію втягувати двох найпотужніших ботів у безпосередню близькість ...;)


Якщо він не може знайти відповідну ціль getTargetDirections(), тоді цікаві речі починають відбуватися. (Наприклад, як зламати все через undefined has no property 0помилку.)
Раміллі,

2

Пенсійний агент ICE, JavaScript

Бажаний колір: indianred

function(me, others, coins) {
    me.arenaLength = me.arenaLength - 1;
    // Calculate the average coin value of bots
    var avg = 2;

    for (var i = 0; i < others.length; i++) {
    avg += others[i][2];
    }

    avg /= others.length;

    // Find nearest coins
    var min = [];
    var min_distance = 100000
    for (var j = 0; j < coins.length; j++) {
    var distance = Math.sqrt(Math.pow(me.locationX - coins[j][0],2) + Math.pow(me.locationY - coins[j][1],2));
    if (distance < min_distance) {
        min_distance = distance;
        min = coins[j];
    }
    }

    if (me.coins <= avg || min_distance < 5) {
    // If own coinage is lower than the average or a coin is very close, find some coins

    // Move straight to the nearest coin
    if (me.locationY != min[1]) {
        if (me.locationY - min[1] > 0) {
        return "north";
        } else {
        return "south";
        }
    } else {
        if (me.locationX - min[0] > 0) {
        return "west";
        } else {
        return "east";
        }
    }
    } else {
        // You have enough money to eat most bots
        // Find the weakest bot
        var weakling = [];
        var weakling_money = 1000000;

        for (var k = 0; k < others.length; k++) {
            if (others[k][2] < weakling_money) {
                weakling_money = others[k][2];
                weakling = others[k];
            }
        }

        // Move to the weakest bot
        if (me.locationY != weakling[1]) {
            if (me.locationY - weakling[1] > 0) {
                return "north";
            } else {
                return "south";
            }
        } else {
            if (me.locationX - weakling[0] > 0) {
                return "west";
            } else {
                return "east";
            }
        }
    }
}

Зараз пенсіонер, цей агент ДВС гірко ставиться до людства. Як результат, пенсіонер ICE зараз націлений на найслабшого бота, зберігаючи його вартість монети вище середнього (відповідно до політики ICE).


2

Жадібний переслідування | Хаскелл

Бажаний колір: #62bda4

import Data.List

f x y c _ bs _
  | [bx,by,_]:_ <- sortByDist x y $ filter ((c>).last) bs = toDir (bx-x,by-y)
f x y _ _ _ cs
  | [cx,cy,_]:_ <- sortByDist x y cs = toDir (cx-x,cy-y)
f _ _ _ _ _ _ = "none"


sortByDist x y = sortOn (\[bx,by,_]-> abs (bx-x) + abs (by-y))

toDir (dx,dy)
  | dx > 0 = "east"
  | dx < 0 = "west"
  | dy > 0 = "south"
  | dy < 0 = "north"
  | otherwise = "none"

Спробуйте в Інтернеті! *

Досить проста стратегія, вибирає перше рішення з:

  • якщо є боти з меншою кількістю монет: виберіть найближчих і рухайтеся до неї
  • якщо є монети: виберіть найближчі та рухайтеся до неї
  • за замовчуванням: залишитися

Бот лише намагається зловити інших ботів або монет, не піклуючись про потенційно більш сильних ботів, які можуть спробувати зловити його.

* Я не знаю JavaScript, але я зробив це з google (можливо, неточний): Спробуйте це в Інтернеті!


6
Цікаво, як він збирається перекласти haskell на js
Luis felipe De jesus Munoz

3
@LuisfelipeDejesusMunoz: Так, і я. Але, на щастя, це не дуже складний код.
ბიმო

@LuisfelipeDejesusMunoz Просто використовуйте Node.JS та process.open(або child_process.spawn, або подібне) з деяким розбором.
користувач202729

@LuisfelipeDejesusMunoz: Я спробував перекласти його і додав посилання, але я не дуже впевнено пишу JavaScript, тому це може бути помилково.
ბიმო

4
@LuisfelipeDejesusMunoz Було б одне, якби це була програма навчання AI на 10 000 ліній, але я думаю, я можу цим керувати (:
Програми Redwolf

1

Монетний магніт | JavaScript

CoinMagnet=(myself,others,coins)=>{
  x=myself.locationX;
  y=myself.locationY;
  power=myself.coins;
  arenaSize=myself.arenaLength;
  dirX=0;
  dirY=0;
  for(i=0;i<coins.length;i++){
    if(i==0){
      dirX+=(coins[i][0]-x)*3
      dirY+=(coins[i][1]-y)*3
    }
    dirX+=(coins[i][0]-x)*2
    dirY+=(coins[i][1]-y)*2
  }
  for(i=0;i<others.length;i++){
    dirX+=Math.ceil(0.85*others[i][2])*(others[i][0]-x)
    dirX+=Math.ceil(0.85*others[i][2])*(others[i][1]-y)
  }
  if(Math.abs(dirX)>Math.abs(dirY)){
    if(dirX>0){return "east";}
    else{return "west";}
  }
  else if(dirY!=0){
    if(dirY>0){return "south";}
    else{return "north";}
  }
  return "none";
}

Цей бот досить німий, він прямує в бік найбільш здобутих монет. Сюди входять монети, які вона не може отримати, оскільки інші боти мають більшу потужність, ніж вона сама.


1

Агент ДВС | Javascript

function(me, others, coins) {
    me.arenaLength = me.arenaLength - 1;
    // Calculate the average coin value of bots
    var avg = 2;

    for (var i = 0; i < others.length; i++) {
        avg += others[i][2];
    }

    avg /= others.length;

    // Find nearest coins
    var min = [];
    var min_distance = 100000
    for (var j = 0; j < coins.length; j++) {
        var distance = Math.sqrt(Math.pow(me.locationX - coins[j][0],2) + Math.pow(me.locationY - coins[j][1],2));
        if (distance < min_distance) {
            min_distance = distance;
            min = coins[j];
        }
    }

    if (me.coins <= avg || min_distance < 5) {
        // If own coinage is lower than the average or a coin is very close, find some coins

        // Move straight to the nearest coin
        if (me.locationY != min[1]) {
            if (me.locationY - min[1] > 0) {
                return "north";
            } else {
                return "south";
            }
        } else {
            if (me.locationX - min[0] > 0) {
                return "west";
            } else {
                return "east";
            }
        }
    } else {
        // You have enough money to eat most bots
        // Check if already on border
        if (me.locationX == 0 || me.locationX == me.arenaLength || me.locationY == 0 || me.locationY == me.arenaLength) {
            // Move anticlockwise around the border
            if (me.locationX == 0 && me.locationY != 0 && me.locationY != me.arenaLength) {
                return "south";
            }
            if (me.locationX == 0 && me.locationY == 0) {
                return "south";
            }

            if (me.locationY == me.arenaLength && me.locationX != 0 && me.locationX != me.arenaLength) {
                return "east";
            }
            if (me.locationX == 0 && me.locationY == me.arenaLength) {
                return "east";
            }

            if (me.locationX == me.arenaLength && me.locationY != 0 && me.locationY != me.arenaLength) {
                return "north";
            }
            if (me.locationX == me.arenaLength && me.locationY == me.arenaLength) {
                return "north";
            }

            if (me.locationY == 0 && me.locationX != 0 && me.locationX != me.arenaLength) {
                return "west";
            }
            if (me.locationX == me.arenaLength && me.locationY == 0) {
                return "west";
            }
        } else {
            // Find the nearest border and move to it
            if (me.locationX <= me.arenaLength - me.locationX) {
                // Move to left border
                return "west";
            } else {
                // Move to right border
                return "east";
            }
        }
    }
}

Який сенс кордону, якщо його не патрулюють? ДВС рухається проти годинникової стрілки навколо кордону, підбираючи будь-яких ботів, які блукають на його шляху.

Перш ніж це зробити, потрібно спочатку з'їсти інших ботів. З цієї причини ICE зберігає монети вище середнього рівня всіх ботів.

Гарантована крадіжка дітей у їхніх батьків ™


Це було б кумедніше, якби це було не так актуально
Дон Тисяча

1

X Позначає пляму | JavaScript

function(me, others, coins){
    if (me.locationY != 0) {
        // If not on X axis
        if (others.every(other => other[1]==me.locationY-1)) {
            // If any in my way
            if (!others.every(other => other[0]==me.locationX-1)) {
                if (me.locationX != 0) {
                    // If no one to my left and not on edge of board
                    return "west"
                } else {
                    return "none"
                }
            } else if (!others.some(other => other[0]==me.locationX+1)) {
                if (me.locationX != me.arenaLength-1) {
                    // If no one to my right and not on edge of board
                    return "east"
                } else {
                    return "none"
                }
            } else {
                // I'm surrounded
                return "none"
            }
        } else {
            // No one in my way
            return "north"
        }
    } else {
        // If on the x axis
        if (!others.some(other => Math.abs(other[0]-me.locationX)==1 && other[1] == me.locationY)) {
            // If no one next to me
            move = ["east","west"][Math.floor(Math.random()*2)]

            // Prevent from falling off the board
            if (move == "east" && me.locationX == me.arenaLength-1) {
                return "west"
            } else if (move == "west" && me.locationX == 0) {
                return "east"
            } else {
                return move
            }
        } else {
            // I'm surrounded
            return "none"
        }
    }
}

X позначає пляму, тому все золото повинно бути на осі x, правда? Мій бот робить лінію для лінії y = 0, а потім залишається там, рухаючись навмання.


Так, справді цікавий метод
програми Redwolf


1
Враховуючи це The arena starts at (0,0) in the upper left corner, ви впевнені, що хочете переїхати, southщоб дістатися y=0?
AdmBorkBork

@AdmBorkBork Спасибі, що могло бути погано
Beta Decay

1

Жар-птах

    function(me,others,coins) {
        var x = me.locationX;
        var y = me.locationY;
        var safe = [true, true, true, true];
        var threats = [];
        var targets = [];
        var opps = [];

        var meTo = (loc) => (Math.abs(x - loc[0]) + Math.abs(y - loc[1]));
        var inSquare = (loc, r) => (Math.abs(loc[0] - x) <= r && Math.abs(loc[1] - y) <= r);
        var distance = (from, loc) => (Math.abs(from[0] - loc[0]) + Math.abs(from[1] - loc[1]));
        var attackRange = (from, check, r) => {
            for (var i = 0; i < check.length; i++) {
                if (distance(check[i], from) == (r || 1)) {
                    return true;
                }
            }
            return false;
        };
        var dirStr = (dir) => (['north','east','south','west'][dir]);

        var i, n, o, p;
        for (i = 0; i < others.length; i++) {
            o = others[i];
            if (o[2] >= me.coins) {
                threats.push(o);
            } else {
                targets.push([o[0], o[1], Math.floor(o[2] * 0.55)]);
            }
        }
        for (i = 1; i < 5; i++) {
            targets.push([coins[i][0], coins[i][1], 2]);
        }
        targets.push([coins[0][0], coins[0][1], 5]);
        if (y === 0 || attackRange([x, y - 1], threats)) {
            safe[0] = false;
        }
        if (x == me.arenaLength - 1 || attackRange([x + 1, y], threats)) {
            safe[1] = false;
        }
        if (y == me.arenaLength - 1 || attackRange([x, y + 1], threats)) {
            safe[2] = false;
        }
        if (x === 0 || attackRange([x - 1, y], threats)) {
            safe[3] = false;
        }
        if (safe.includes(false)) {
            if (!(safe[0]) && safe[2]) {
               opps.push(2);
            }
            if (!(safe[1]) && safe[3]) {
                opps.push(3);
            }
            if (!(safe[2]) && safe[0]) {
                opps.push(0);
            }
            if (!(safe[3]) && safe[1]) {
                opps.push(1);
            }
        } else {
            targets.sort((a,b)=>(meTo(a) - meTo(b)));
            o = targets[0];
            if (o[0] == x) {
                if (o[1] < y) {
                    return 'north';
                } else {
                    return 'south';
                }
            } else if (o[1] == y) {
                if (o[0] < x) {
                    return 'west';
                } else {
                    return 'east';
                }
            } else if (Math.abs(o[0] - x) < Math.abs(o[1] - y)) {
                if (o[1] < y) {
                    return 'north';
                } else {
                    return 'south';
                }
            } else if (Math.abs(o[0] - x) > Math.abs(o[1] - y)) {
                if (o[0] < x) {
                    return 'west';
                } else {
                    return 'east';
                }
            }
        }
        console.log(safe[opps[0]]);
        var lx, ly;
        for (i = 0; i < opps.length; i++) {
            if (opps[i] === 0) {
                lx = x;
                ly = y - 1;
            }
            if (opps[i] == 1) {
                lx = x + 1;
                ly = y;
            }
            if (opps[i] == 2) {
                lx = x;
                ly = y + 1;
            }
            if (opps[i] == 3) {
                lx = x - 1;
                ly = y;
            }
            if (attackRange([lx, ly], targets, 0)) {
                return dirStr(opps[i]);
            }
        }
        return dirStr(opps[0]);
    }

Повністю оновлений, щоб бути більш смертельним, ніж раніше (:


2
Мій абсолютний програш бота
Redwolf Programs

Це не орієнтовано на них, це уникає
Redwolf Programs

Пробачте, я неправильно зрозумів
Beta Decay

1

А-Шлях-у | JavaScript

Кращим кольором для цього бота є #0077b3.

 run: function (me, others, coins)
{
    var X_INDEX = 0;
    var Y_INDEX = 1;
    var COIN_INDEX = 2;

    var GOLD_POINTS = 5;
    var SILVER_POINTS = 2;

    var NORTH = 0;
    var SOUTH = 1;
    var WEST = 2;
    var EAST = 3;
    var IDLE = 4;
    var MOVE_COMMANDS_COUNT = IDLE+1;

    var MAP_TYPE_BLANK = 0;
    var MAP_TYPE_BOT = 1;
    var MAP_TYPE_GOLD_COIN = 2;
    var MAP_TYPE_SILVER_COIN = 3;

    var MIDGAME_THRESHOLD = 25;

    var PATH_FINDING_MAX_STEPS = 10000;
    var offsets = [[0,-1],[1,0],[0,1],[-1,0]];

function randInt(min,max)
    {
        return  Math.floor(Math.random() * ((max - min) + 1)) + min;
    }


    /**
     * Find a path using a*, returns the direction to take from the starting position coupled with a metric describing the cost of the path
     */
function pathFind(startX,startY,targetX,targetY,map,mapSize)
    {
        var i;
        var j;

        // shuffleIndecies to make path selection slightly random
        var indecies = [0,1,2,3];
        var shuffleIndecies = new Array(4);
        for (j=0;j<4;j++)
        {
            var randomIndex = randInt(0,3-j);
            shuffleIndecies[j] = indecies[randomIndex];
            indecies[randomIndex] = indecies[0];
            var lastElementIndex = 4-j-1;
            indecies[0] = indecies[lastElementIndex];
        }

        // A*
        if (!(startX===targetX && startY===targetY))
        {

            var tileX = new Array(PATH_FINDING_MAX_STEPS);
            var tileY = new Array(PATH_FINDING_MAX_STEPS);
             var fscore = new Array(PATH_FINDING_MAX_STEPS);
             var gscore = new Array(PATH_FINDING_MAX_STEPS);
             var openList = new Array(PATH_FINDING_MAX_STEPS);
             var tileParent = new Array(PATH_FINDING_MAX_STEPS);
             var tileIsClosed = new Array(mapSize);

             for (i = 0;i<PATH_FINDING_MAX_STEPS;i++)
             {
                 tileX[i]=0;
                 tileY[i]=0;
                 fscore[i]=0;
                 gscore[i]=0;
                 openList[i]=0;
                 tileParent[i]=0;
             }


             for (i = 0;i<mapSize;i++)
             {
                 var newArray = new Array(mapSize);
                 tileIsClosed[i] = newArray;
                 for (j = 0;j<mapSize;j++)
                 {
                     tileIsClosed[i][j] = 0;
                 }
             }

             var currentIndex = -1;     

            var openListSize=1;
            var tileId=1;

            tileX[0]=targetX;
            tileY[0]=targetY;
            fscore[0]=1;
            gscore[0]=map[targetX][targetY].negativeWeight;



            do
            {
              var currentBestIndex=-1;
              var currentBestScore=2147483647;
              //  Look for the lowest F cost square on the open list
              for (var ii=0;ii<openListSize;ii++)
              {
                if (fscore[openList[ii]]<currentBestScore)
                {
                  currentBestScore=fscore[openList[ii]];
                  currentBestIndex=ii;
                }
              }
              if (currentBestIndex===-1)
              {
                break;
              }
              currentIndex=openList[currentBestIndex];
              var currentTileX=tileX[currentIndex];
              var currentTileY=tileY[currentIndex];

              // found path
              if (startX===currentTileX && startY===currentTileY)
              {
                break;
              }

              // if not in closed list
              if (tileIsClosed[currentTileX][currentTileY]===0)
              {
                    // Switch it to the closed list.
                    tileIsClosed[currentTileX][currentTileY]=1;
                    // remove from openlist
                    openList[currentBestIndex]=openList[--openListSize];   

                    // add neighbours to the open list if necessary
                    for (j=0;j<4;j++)
                    {
                        i = shuffleIndecies[j];

                        var surroundingCurrentTileX=currentTileX+offsets[i][0];
                        var surroundingCurrentTileY=currentTileY+offsets[i][1];
                        if (surroundingCurrentTileX>=0 && surroundingCurrentTileX<mapSize &&
                            surroundingCurrentTileY>=0 && surroundingCurrentTileY<mapSize )
                        {
                          tileX[tileId]=surroundingCurrentTileX;
                          tileY[tileId]=surroundingCurrentTileY;

                          var surroundingCurrentGscore=gscore[currentIndex] + map[surroundingCurrentTileX][surroundingCurrentTileY].negativeWeight;
                          gscore[tileId]=surroundingCurrentGscore;
                          fscore[tileId]=surroundingCurrentGscore+Math.abs( surroundingCurrentTileX-startX)+Math.abs( surroundingCurrentTileY-startY);
                          tileParent[tileId]=currentIndex;
                          openList[openListSize++]=tileId++;
                        }
                    }
              }
              else
              {
              // remove from openlist
              openList[currentBestIndex]=openList[--openListSize];    
              }
            } while(true);

            if (tileX[tileParent[currentIndex]]<startX) return {moveDirection:WEST, pathLength:currentIndex, pathScore:gscore[currentIndex]+currentIndex/4};
            else if (tileX[tileParent[currentIndex]]>startX) return {moveDirection:EAST, pathLength:currentIndex, pathScore:gscore[currentIndex]+currentIndex/4};
            else if (tileY[tileParent[currentIndex]]<startY) return {moveDirection:NORTH, pathLength:currentIndex, pathScore:gscore[currentIndex]+currentIndex/4};
            else if (tileY[tileParent[currentIndex]]>startY) return {moveDirection:SOUTH, pathLength:currentIndex, pathScore:gscore[currentIndex]+currentIndex/4};
        }
        console.log("Path finding failed");
        return {moveDirection:IDLE, pathLength:0, pathScore:2147483647};
     }

function process(info,bots,coins)
    {
        var i;
        var j;
        var k;
        var x;
        var y;

        // initialise map
        var mapSize = info.arenaLength;
        var map = new Array(mapSize);
        for (i = 0;i < info.arenaLength;i++)
        {
            var newArray = new Array(info.arenaLength);
            map[i] =  newArray;
            for (j = 0;j < mapSize;j++)
            {
                map[i][j] = {type:MAP_TYPE_BLANK, coins: 0 , negativeWeight:i===0||i===mapSize-1||j===0||j===mapSize-1?3:1};
            }
        }

        // populate map with bots
        for (i = 0 ; i<bots.length;i++)
        {
            map[bots[i][X_INDEX]][bots[i][Y_INDEX]].type = MAP_TYPE_BOT;
            map[bots[i][X_INDEX]][bots[i][Y_INDEX]].coins = bots[i][COIN_INDEX];

            for (j=-1;j<2;j++)
            {
                x = bots[i][X_INDEX] + j;
                if (x>=0 && x < mapSize)
                {
                    for(k=-1;k<2;k++)
                    {
                        if (Math.abs((k+j)%2) === 1)
                        {
                            y = bots[i][Y_INDEX] + k;
                            if (y>=0 && y< mapSize )
                            {
                                // are we adjacent the bot or potentially will be?
                                if (Math.abs(info.locationX-x)<=1 && Math.abs(info.locationY-y)<=1)
                                {
                                    // make the cell significantly less attractive when the bot is stronger than us, or
                                    // make the cell slightly more attactive when the bot is weaker than us, or
                                    // not change if the bot has no coins
                                    map[x][y].negativeWeight+= bots[i][COIN_INDEX] >= info.coins?100000:(bots[i][COIN_INDEX]===0?0:-1);
                                }
                                // another bot is not a direct threat/target
                                else
                                {
                                    // make the cell moderately less attractive when the bot is stronger than us, or
                                    // make the cell slightly more attactive when the bot is weaker than us, or
                                    // not change if the bot has no coins
                                    map[x][y].negativeWeight+= bots[i][COIN_INDEX] >= info.coins?3:(bots[i][COIN_INDEX]===0?0:-1);
                                }
                            }
                        }
                    }
                }
            }
        }

        // populate map with coins
        for (i = 0 ; i<coins.length;i++)
        {
            map[coins[i][X_INDEX]][coins[i][Y_INDEX]].type = i === 0?MAP_TYPE_GOLD_COIN:MAP_TYPE_SILVER_COIN;
            map[coins[i][X_INDEX]][coins[i][Y_INDEX]].coins = i === 0?GOLD_POINTS:SILVER_POINTS;

            // check to see whether bots are adjacent to the coin
            for (j=-1;j<2;j++)
            {
                x = coins[i][X_INDEX] + j;
                if (x>=0 && x < mapSize)
                {
                    for(k=-1;k<2;k++)
                    {
                        if ((k+j)%2 === 1)
                        {
                            y = coins[i][Y_INDEX] + k;
                            if (y>=0 && y< mapSize )
                            {
                                if (map[x][y].type === MAP_TYPE_BOT)
                                {
                                    // this coin looks like a trap as a stronger bot is adjacent to it
                                    if (map[x][y].coins >= info.coins)
                                    {
                                        map[coins[i][X_INDEX]][coins[i][Y_INDEX]].negativeWeight+=100000;
                                    }
                                    else
                                    {
                                        // are we adjacent the coin? we might be able to kill another bot if it trys to get the coin
                                        if (Math.abs(info.locationX-coins[i][X_INDEX])<=1 && Math.abs(info.locationY-coins[i][Y_INDEX])<=1)
                                        {
                                            map[coins[i][X_INDEX]][coins[i][Y_INDEX]].negativeWeight+=-20;
                                        }
                                        // another bot is likely to get this coin... make it less attractive
                                        else
                                        {
                                            map[coins[i][X_INDEX]][coins[i][Y_INDEX]].negativeWeight=+100;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // add the coin attractiveness, more for gold coins
            map[coins[i][X_INDEX]][coins[i][Y_INDEX]].negativeWeight += i === 0?-20:-10;
        }


        var pathBest = {moveDirection:IDLE, pathLength: 2147483647, pathScore: 2147483647};

        if (info.coins > MIDGAME_THRESHOLD)
        {
            var viableCoinCount =0;
            var viableCoins = new Array(5); 


            // find coins that are reachable before any other bot
            outer1:
            for (j = 0 ; j<coins.length;j++)
            {
                var contention = 0;

                var myDistanceToCoin = Math.abs(info.locationX-coins[j][X_INDEX]) + Math.abs(info.locationY-coins[j][Y_INDEX]);

                for (i = 0 ; i<bots.length;i++)
                {
                    var dist = Math.abs(bots[i][X_INDEX]-coins[j][X_INDEX]) + Math.abs(bots[i][Y_INDEX]-coins[j][Y_INDEX]);
                    if (dist < myDistanceToCoin)
                    {
                        continue outer1;
                    }
                }
                viableCoins[viableCoinCount++] = j;
            }

            // no coins are reachable before another bot so find the cell that is furthest away from any bot and head there
            if (viableCoinCount ===0)
            {
                var mostIsolatedCellX = mapSize/2;
                var mostIsolatedCellY = mapSize/2;
                var mostIsolatedCellMinBotDistance = 0;

                for (x=5;x<mapSize-5;x++)
                {
                    for (y=5;y<mapSize-5;y++)
                    {
                        if (x!= info.locationX && y!=info.locationY)
                        {

                            // ignore coin attractiveness
                            map[x][y].negativeWeight = map[x][y].negativeWeight<-4?map[x][y].negativeWeight:1;


                            var currentCellMinBotDistance = 2147483647;

                            for (i = 0 ; i<bots.length;i++)
                            {
                                var dist = Math.abs(bots[i][X_INDEX]-x) + Math.abs(bots[i][Y_INDEX]-y) + Math.abs(info.locationX-x) + Math.abs(info.locationY-y);
                                if (dist < currentCellMinBotDistance )
                                {
                                    {
                                        currentCellMinBotDistance = dist;                           
                                        if (currentCellMinBotDistance>mostIsolatedCellMinBotDistance)
                                        {
                                            mostIsolatedCellMinBotDistance = currentCellMinBotDistance;
                                            mostIsolatedCellX=x;
                                            mostIsolatedCellY=y;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // attempt to find path to most isolated cell
                pathBest = pathFind(info.locationX, info.locationY, mostIsolatedCellX,mostIsolatedCellY, map, mapSize);
            }

            // attempt to find paths to each viable coin, keeping the best result
            for (i = 0 ; i<viableCoinCount;i++)
            {
                var path = pathFind(info.locationX, info.locationY, coins[viableCoins[i]][X_INDEX],coins[viableCoins[i]][Y_INDEX], map, mapSize);
                if (path.pathScore < pathBest.pathScore)
                {
                    pathBest = path;
                }
            }
        }
        else
        {
            // attempt to find paths to each coin, keeping the best result
            for (i = 0 ; i<coins.length;i++)
            {
                var path = pathFind(info.locationX, info.locationY, coins[i][X_INDEX],coins[i][Y_INDEX], map, mapSize);
                if (path.pathScore < pathBest.pathScore)
                {
                    pathBest = path;
                }
            }
        }


        var move = IDLE;
        if (pathBest.pathLength === 2147483647)
        {
            outer:
            for (i=0;i<MOVE_COMMANDS_COUNT;i++)
            {
                switch (i)
                {
                    case NORTH:
                        if (info.locationY-1 < 0)
                        {
                            continue;
                        }
                        move = i;
                        break outer;
                    case SOUTH:
                        if (info.locationY+1 === info.arenaLength)
                        {
                            continue;
                        }
                        move = i;
                        break outer;
                    case WEST:
                        if (info.locationX-1 < 0)
                        {
                            continue;
                        }
                        move = i;
                        break outer;
                    case EAST:
                        if (info.locationX+1 === info.arenaLength)
                        {
                            continue;
                        }
                        move = i;
                        break outer;
                    case IDLE:
                        move = i;
                        break;
                    default:
                }
            }
        }
        else
        {
            move = pathBest.moveDirection;
        }

        switch (move)
        {
        case NORTH:
            return "north";
        case SOUTH:
            return "south";
        case EAST:
            return "east";
        case WEST:
            return "west";
        default:
            return "none";
        }
    }
    return process(me, others, coins);
}

Цей бот використовує пошук шляху в поєднанні з картою бажаностей комірок, щоб уникнути ботів, які могли б нас убити, ідіть за близькими монетами, а не з пастками і найменш ризикованими.

Це, здається, не є претендентом на виграшне місце, але все-таки тримається свого власного і буде живим наприкінці матчу, якщо він виживе перед початковим боєм.

Зараз Bot має ігрову стратегію середнього та пізнього періоду, яка ігнорує монети, до яких не може дійти до інших ботів, а якщо не може перейти до будь-якої монети, то переходить до найближчої клітини, яка знаходиться найдалі від усіх інших ботів, які сильніші за себе.

Тепер він має шанс на перемогу.

Зауважте, вибачте за шалений код, я автоматично перетворив його з Java


Не забудьте невдовзі позбутися помилок та / або оновлень, 18 годин до строку!
Програми Redwolf

@RedwolfPrograms Ви помітили помилку? якщо так, будь ласка, повідомте мене, щоб я могла виправити. Спасибі
Moogie

Ні, але ніколи не знаєш. Просто переконайтесь, що я перевірив, оскільки я бачив, що багато ботів втрачають через одне неправильне число чи неправильну функцію або неправильно вводять помилку, ніж я можу порахувати
Redwolf Programs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.