Gold Collector KoTH


48

Uwaga: ankieta dla ulubionych społeczności zostanie wkrótce opublikowana

W tym KoTH celem jest bycie ostatnim żyjącym botem. Monety będą umieszczane w losowych obszarach, a twój bot musi najpierw zdobyć monety. Jeśli bot trafi na innego bota, wygrywa bot z większą ilością monet, a drugi umiera. Więcej szczegółów poniżej.

Rodzaje monet

Będą 2 rodzaje monet: złote i srebrne. Złoto dodaje 5 siły do ​​siły bota, a srebro dodaje 2. Po zebraniu monety kolejna moneta jest umieszczana w innym miejscu na planszy. W danym momencie na arenie jest jedna złota moneta i cztery srebrne monety.

Zderzenia botów

W przypadku dwóch botów próbujących zająć to samo miejsce, ten z większą liczbą monet pozostanie, a ten z mniejszą liczbą ... nie. Zwycięski bot zyska 85% monet przeciwnika (zaokrąglone w górę). Jeśli są związane, oboje giną. Jeśli trzy lub więcej osób spróbuje zająć to samo miejsce, najpotężniejszy wygrywa i otrzymuje 85% wszystkich monet innego bota. W przypadku, gdy najpotężniejszym botem jest remis, wszystkie boty giną, próbując wejść w przestrzeń.

Arena

Długość boku areny jest obliczana za pomocą 4 + botCount. Podczas umieszczania botów na początku gry wybiera się losowe miejsca. System zapewnia, że ​​żadne boty nie wystartują w tym samym miejscu lub obok siebie. Monety generują losowo, z wyłączeniem kwadratu 3 na 3 wyśrodkowanego na każdym bocie. Jeśli bot zostanie znaleziony poza areną, natychmiast umiera. Arena zaczyna się od (0,0) lub na północny zachód, w lewym górnym rogu, a lokalizacja bota jest zawsze liczbą całkowitą.

Twój bot

Twój bot powinien być funkcją w dowolnym języku obiektowym, który ma tablice, liczby całkowite, łańcuchy i funkcje. Pamiętaj, że wszystkie zgłoszenia zostaną przekonwertowane na Javascript, aby uprościć sprawę. Aby przechowywać informacje między ruchami, użyj botNotes.storeData(key, value)i botNotes.getData(key, value). Nie możesz przechowywać ani uzyskiwać dostępu do danych w jakikolwiek inny sposób niż ten, który jest zapewniany przez parametry i botNotes. Należy utworzyć funkcję, kiedy nazywa, zwraca łańcuch north, east, south, west, lub none. Będą 3 argumenty dla funkcji:

  • Obiekt z czterech liczb całkowitych ( locationX, locationY, coins, arenaLength), aktualna lokalizacja, swoje monety, a długość rzędu

  • Wielowymiarowa tablica ze współrzędnymi X i Y innych botów i ich liczbą monet, np.[[0,5,4],[4,7,1],[7,4,12]]

  • Tablica z wymienionymi lokalizacjami monet (złoto jest zawsze pierwsze)

To wyzwanie króla wzgórza, zabronione Standardowe Luki . Twoja funkcja będzie uruchamiana kilka tysięcy razy, za każdym razem dozwolony jeden „ruch”. Pamiętaj, że jeśli gra przekroczy 20 000 ruchów , wygrywa bot z największą liczbą monet. Zostanie to zrobione 8000 razy, aby usunąć losowość.

Pokój czatu: https://chat.stackexchange.com/rooms/81347/gold-collectors-koth

Nagrody:

Pierwsze miejsce: 100-punktowa nagroda
Społeczność Ulubiona: 15-punktowa zaakceptowana odpowiedź

Zwycięzcy:

Pierwsze miejsce: TBTPTGCBCBA
Drugie miejsce: Big King Little Hill
Trzecie miejsce: Potencjalnie zwycięski
Czwarte miejsce: Uprzejmy, niedowidzący pijany bot
Piąte miejsce: Moneta bezpieczeństwa


6
„Pamiętaj, że wszystkie zgłoszenia zostaną przekonwertowane na Javascript, aby uprościć sprawę”. Jak to ma działać? Czy dokonujesz konwersji?
Laikoni,

21
Nie ma nic złego w tym, że Koth zezwala tylko na jeden język, zwłaszcza taki tak szeroko rozpowszechniony jak JavaScript. Zamiast dwuznacznie „konwertować” odpowiedzi na JavaScript (prawdopodobnie samodzielnie i ręcznie), powinieneś po prostu ograniczyć wyzwanie tylko do JS. W końcu mieliśmy mnóstwo Kothów opartych wyłącznie na Javie i Pythona.
Skidsdev,

2
Wersja tego, w której kontrolujesz przyspieszenie zamiast pozycji, byłaby całkiem fajna.
akozi

12
Do wszystkich: Jest już zbyt wiele komentarzy. Nie zostawiaj niepotrzebnych komentarzy, takich jak „+1, miły bot” , i usuń swoje komentarze, jeśli są zbędne . Nie jesteśmy typową witryną pytań i odpowiedzi, ale nikt nie lubi czytać setek poleceń.
user202729,

5
(Na moje własne pytanie): Według NP na czacie, jest to ten drugi: wszystkie boty się poruszają, następnie wszystkie konflikty zostają rozwiązane, następnie następuje odbiór monet, a następnie umieszczane są wszystkie nowe monety.
BradC,

Odpowiedzi:


26

BaitBot - JavaScript Node.JS

Po co męczyć się i gonić, skoro nigdy nie można złapać? Zamiast tego BaitBot znajduje najbliższą monetę i czeka, aż słabszy bot również do niej podejdzie. Gdy oba są obok siebie, baitBot wybiera monetę, zakładając, że zrobi to również słabszy bot. Jeśli baitBot czeka i zbliża się silniejszy bot, po prostu chwyta monetę i jeździ na desce. Spróbuj mnie!

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
Ha, to fajny pomysł, podoba mi się.
sundar

To podejście jest całkiem fajne ... nie, bardzo fajne
Redwolf Programs

1
BaitBot potrzebuje nearestThreat && distanceTo(nearestThreat)raczej niż tylko distanceTo(nearestThreat). Zawodzi, gdy nie ma zagrożenia.
Programy Redwolf,

1
Tak nearestThreatjest undefined, gdy wszystkie inne boty mają więcej punktów niż twój.
Noc 2

1
Cóż, dostaję powiadomienia jak [10] Bot Bait Bot tired of this world, and jumped off its edgew moim dzienniku zdarzeń
Redwolf Programs

17

Potencjalnie zwycięski | JavaScript

Preferowany kolor tego bota to #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];
}

(Przepraszamy za niedbałe formatowanie, wcięcie 4 spacji dla tej witryny nie pasuje do mojego zwyczaju używania tabulatorów).

Szorstkie wyjaśnienie

Niniejszym rezygnuję z próby aktualizacji wyjaśnienia formuł. Współczynniki ciągle się zmieniają i trudno jest aktualizować wyjaśnienie. Wyjaśnię więc ogólną zasadę.

Każda moneta i każdy bot generuje pole siłowe z pewnym potencjałem. Po prostu dodam potencjały ze wszystkiego razem, a następnie bot idzie tam, gdzie potencjał jest najniższy. (Oczywiście ten pomysł został skradziony z fizyki.)

Używam dwóch rodzajów potencjałów. Pierwszy to pseudo-grawitacyjny (działający w dowolnym zakresie), z Kjest „siła” w tej dziedzinie, a wraz z tym wybór znaku, potencjał jest atrakcyjny. Rtutaj (i wszędzie indziej) jest odległością w taksówki metryczny,r = | x₁ - x₂ | + | y₁ - y₂ | .

U=-kr+1511+n.

Używam k = 40 dla złotych monet i k = 10 dla srebrnych monet. n to liczba botów, które są bliżej konkretnej monety niż my. W przeciwnym razie absolutnie ignorujemy pozostałe boty (jeśli przeszkadzamy silniejszemu botowi, uciekamy, ale to wszystko). Cenię złote monety za więcej, niż są warte, bo inaczej boty, które idą przede wszystkim po złoto cały czas mnie biją.

Drugi potencjał jest wykładniczo niszczący (który skutecznie działa tylko na bardzo małe odległości). Jest to generowane przez inne, głównie silniejsze boty.

Dają one pole o Siła ta jest nadmiernie silna w zakresie 0-1, ale rozpada się prawie na nic przy większych odległościach. (Odległość + 1 oznacza zmniejszenie siły o 1/20.)

U=-5×1400mi-3)r.

Na ogół nie atakujemy innych botów celowo (oczywiście jeśli staną nam na drodze i nadepniemy na nie, to ich wina), ale istnieje taka możliwość. Jeśli zostaną spełnione trudne warunki, możemy przejść do trybu polowania , koncentrując się na jednym bocie. Aby przejść do trybu polowania:

  1. Musimy mieć co najmniej 25 monet. (Najpierw musimy zdobyć monety.)
  2. Muszą mieć co najwyżej (nasze monety - 5) monet i co najmniej 10 monet. (Nie chcemy polować na kogoś, kto złapie jedną monetę i nagle stanie się potężniejszy, i nie chcemy też ścigać botów o zerowej monecie).
  3. Musimy pozostawać w tyle za obecnie wiodącym botem o co najmniej 1/10 jego monet. (Musisz mieć szczęście, aby coś upolować, więc nie trzeba rozdawać dobrej pozycji tylko za próbę szczęścia.)
  4. Nie wolno nam odnawiać polowania (patrz poniżej).

Jeśli wszystkie te warunki zostaną spełnione, tryb polowania zostanie aktywowany. Przez następne 10 rund upolowany bot emituje tylko potencjalne Po upływie tych 10 rund wchodzimy w czas odnowienia polowania, podczas którego nie możemy ponownie wejść w tryb polowania. (To ma nas powstrzymać od niekończącego się i bezowocnego ścigania jednego bota, podczas gdy inne szczęśliwie chwytają monety.) Czas odnowienia polowania wynosi 20 rund, gdy mamy 25 monet, i wzrasta o 20 monet za każde podwojenie tego. (Innymi słowy, czas odnowienia to

U=-150mi-r.
20(1 + log2(c / 25)).) (Używamy tego, ponieważ w końcowej fazie gry wszystkie boty, na które można polować, najprawdopodobniej są martwe, a więc każde polowanie będzie najprawdopodobniej daremne. Z tego powodu chcemy ograniczyć zmarnowany czas. Ale czasami szczęście jest spóźnione jedzenie w grze może zmienić wszystko, więc zachowujemy taką możliwość).

Na koniec cała arena jest umieszczona w nieskończonej potencjalnej studni, co zapobiega ucieczce bota.


Myślę, że ten bot prawdopodobnie przewyższa również mój ważony ruch.
fəˈnɛtɪk

@ fəˈnɛtɪk - So I I :—). Myślę, że ten może obsługiwać inne boty nieco lepiej. (Również nie jest to „oślepienie” monetą na sąsiednim kwadracie). Ale zdecydowanie dałem ci +1, ponieważ jestem wielkim fanem tego pomysłu.
Ramillies,

Czy możesz zastosować do tego zasadę najmniejszego działania?
Rozpad beta w dniu

@BetaDecay: Nie dość, obawiam się, że rachunek różniczkowy nie reaguje dobrze na takie dyskretne problemy jak ten. Nawet w ciągłym przypadku nie byłoby to trywialne (ze względu na ustaloną wielkość prędkości), ale może być wykonalne po magicznej współrzędnej biegunowej.
Ramillies,

4
To jest fajne. Nie jestem jednak pewien, czy ryzyko jest monotonicznie związane z odległością, wydaje się, że zagrożenie 2 odległości dalej jest bardziej prawdopodobne, że zabije cię niż jedno sąsiadujące, ponieważ w tym drugim przypadku jedno z was musi pozostać nieruchome, aby doszło do kolizji.
Cain

16

Algorytm uczenia się pierwszej generacji | JavaScript (Node.js)

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

Wypróbuj online!

Czy widziałeś kiedyś te algorytmy uczenia się gry? Często poruszają się prawie losowo w pierwszych kilku pokoleniach ...


LOL ... To może nadal działać!
Programy Redwolf

2
Większość algorytmów uczenia się działa dosłownie losowo przez kilka pierwszych iteracji, a nie tylko prawie losowo.
fəˈnɛtɪk

Zgadnij co? Bot ten otrzymał średnio prawie 0,22 monety na rundę!
Programy Redwolf,

16

Big King Little Hill | 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])
}

Wypróbuj online!

Big King Little Hill podejmuje decyzje w oparciu o „strefy kontroli”. Będzie ścigał tylko monety znajdujące się w strefie kontroli, co oznacza, że ​​może dotrzeć do monety, zanim jakikolwiek inny bot będzie mógł. Gdy w strefie kontroli nie ma monet, porusza się, aby zmaksymalizować wielkość strefy kontroli. Big King Little Hill oblicza strefę kontroli każdego z 5 możliwych ruchów i preferuje ruchy, które maksymalizują rozmiar jej strefy kontroli. W ten sposób Big King Little Hill ostatecznie osiąga lokalne maksimum kontroli (małe wzgórze) i czeka na wygenerowanie monety w swojej strefie. Dodatkowo, Big King Little Hill odrzuca każdy ruch, który może doprowadzić do jego śmierci, chyba że nie ma alternatywy.

Big King Little Hill jest pesymistą (woli termin realista), ponieważ nie zawraca sobie głowy żadną monetą, której zdobycie nie jest pewne. Jest także pacyfistą, ponieważ w żadnym sensie nie ściga słabszych botów (choć może natknąć się na jednego, jeśli przeszkadza). Wreszcie, Big King Little Hill jest tchórzem, który nie zagrozi własnemu życiu za jakąkolwiek nagrodę, chyba że absolutnie musi.


1
Witamy w PPCG! To bardzo dobry bot = D
Luis Felipe De Jesus Munoz

Tak myślałem dla bota. Dobra robota.
Jo.

10

Moneta bezpieczeństwa | 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";}
  }
}

Ten bot zmierza prosto w stronę ważonej monety (wartość / odległość), której nie może umrzeć, osiągając jednocześnie lub po innym bocie. Jeśli nie ma ważnej monety z tą właściwością , siedzi ona tam, gdzie jest bot, porusza się teraz w losowo bezpiecznym kierunku (bezpieczeństwo oznacza, że ​​jeśli bot ruszy w jego kierunku, bezpieczna moneta nie może się zderzyć. Pozwala to botowi zamienić się miejscami z innym botem, jeśli bezpośrednio obok niego), ważony w kierunku środka areny.


1
Huh, to może faktycznie wygrać. Chociaż istnieje wiele botów
Redwolf Programs

Ta metoda będzie miała więcej problemów, im bardziej nierównomiernie umieszczone zostaną wrogie boty o wyższej lub równej wartości.
fəˈnɛtɪk

1
Cóż, prawdopodobnie wszyscy będą zbliżać się do najbliższej im monety / złotej monety.
Redwolf Programs,

Będzie dobrze, jeśli uda mu się zdobyć trochę monet na początku.
fəˈnɛtɪk

I to jest głównie szczęście, ponieważ miejsce generowania monet jest losowo ustalane
Redwolf Programs

10

Bot, który gra ostrożnie, ale może być agresywny | JavaScript

Preferowany kolor: #F24100

Uwaga: Chociaż ten bot zajął 1. miejsce, wynika to z połączenia z „Feudal Noble” na końcu i zjedzenia go, by zdobyć więcej monet. W przeciwnym razie ten bot byłby trzeci. Jeśli interesują Cię boty, które są silniejsze indywidualnie, sprawdź Potencjalnie Zwycięską i Little 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;
}

Ten bot (znany również jako „TBTPTGCBCBA”) próbuje podjąć najlepszą możliwą decyzję, generując wynik dla każdego możliwego ruchu i wybiera ruch z wyższym wynikiem dla każdej tury.

System punktacji zawiera wiele szczegółów, które ewoluują od początku wyzwania. Można je ogólnie opisać w następujący sposób:

  • Im bliżej monety są możliwe ruchy, tym więcej punktów uzyska ruch. Jeśli na monecie nie ma innych możliwych uczestników, wynik jest jeszcze wyższy. Jeśli moneta ma innych możliwych uczestników, wynik jest niższy.
  • Jeśli inny bot jest blisko możliwego ruchu i ma mniej monet, w zależności od fazy gry, może to oznaczać więcej punktów za ten ruch. Dlatego przypadkiem „TBTPTGCBCBA” zjada kilka innych botów w każdej grze.
  • Jeśli inny bot jest bliski możliwemu ruchowi z równą lub większą liczbą punktów, ruch ten otrzymuje wystarczającą liczbę punktów ujemnych, aby uniknąć śmierci. Oczywiście mogą zdarzyć się przypadki, że wszystkie możliwe ruchy są złe i nie da się uniknąć śmierci, ale jest to bardzo rzadkie.
  • Istnieje mechanizm śledzenia liczby botów na środku planszy przez ostatnie 20 tur. Jeśli średnia jest wystarczająco niska, wszystkie ruchy w kierunku monet pośrodku uzyskują wyższy wynik, a jeśli średnia jest wysoka, wówczas wszystkie ruchy w kierunku monet pośrodku otrzymują niższy wynik. Mechanizm ten pozwala uniknąć konfliktów z „Feudal Noble”. Ponieważ „Feudal Noble” jest zawsze w środku (chyba, że ​​jest ścigany), średnia liczba botów w środku rośnie, a „TBTPTGCBCBA” rozumie, jak unikać środka, jeśli jest lepsza opcja poza obszarem środkowym. Jeśli „Feudal Noble” umrze, średnia spada, a „TBTPTGCBCBA” rozumie, że może użyć środka.
  • Istnieją pewne czynniki, które dynamicznie zmieniają się w zależności od fazy gry (wykryte na podstawie liczby żywych botów), czynniki te wpływają na punktację w każdym z powyższych przedmiotów.
  • Ten bot ma specjalną zdolność. Z czasem męczy go samolubstwo „szlachcica feudalnego” i ucisk chłopów. W odpowiednim momencie dojdzie do zakończenia nieprzyjemnego systemu feudalizmu. Udana próba nie tylko pomaga biednym chłopom, ale także zapewnia wyższą szansę na wygraną dzięki monetom pobranym z „Feudal Noble”.

Wydaje się o wiele bardziej ... inteligentny od innych
Redwolf Programs

5
Lubię potwory z params
Redwolf Programs

9

The AntiCapitalist | JavaScript

Nie ma motywacji, by szukać monet, ale stara się postawić dokładnie między dwoma najbogatszymi botami z taką samą ilością pieniędzy, w nadziei, że polują na niego i ostatecznie go złapią w tym samym czasie, zabierając ze sobą dwóch kapitalistów, gdy umrze. . Nie opiera się aktywnie zdobywaniu monet, więc może stać się bardziej soczystym celem.

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

W Potencjalnie Zwycięskim mamy dwa pola: dolne i dolne. Natura nie jest jednak taka skomplikowana. Czas zjednoczyć te dwa pola, aby stworzyć Teorię Wielkiej Unifikacji .

Po pierwsze musimy ustalić, jaki jest potencjał tego pola. Zakładając, że nasz własny bot nie wpływa w żaden sposób na pole, możemy to napisać jako:

V.=nkn(mikn2)-100(x-xn)2)+mikn2)-100(y-yn)2))

kn(xn,yn)

Względną właściwość obiektu oblicza się w następujący sposób:

k=doobiektdomnie

dodomnie=dosamego siebie+1dosamego siebie

Nazwijmy to korekcję częścią Zmodyfikowanej Dynamiki Betańskiej (MOBD) .

Możemy również znaleźć energię kinetyczną jako:

T.=12)domnie(x˙2)+y˙2))

Możemy teraz obliczyć akcję:

Akcja=zab(T.-V.)ret=zab(12)domnie(x˙2)+y˙2))-nkn(mikn2)-100(x-xn)2)+mikn2)-100(y-yn)2)))ret

I tak Lagrangian naszego bota w dziedzinie monet-botów to:

L.=12)domnie(x˙2)+y˙2))-nkn(mikn2)-100(x-xn)2)+mikn2)-100(y-yn)2))

Teraz musimy rozwiązać równania Eulera-Lagrange'a:

reretL.x˙=L.x

i:

reretL.y˙=L.y

Więc:

reretL.x˙=reret[domniex˙]=domniex¨

L.x=n200kn(x-xn)mikn2)-100(x-xn)2)

x¨=n200kndomnie(x-xn)mikn2)-100(x-xn)2)

I również:

reretL.y˙=reret[domniey˙]=domniey¨

L.y=n200kn(y-yn)mikn2)-100(y-yn)2)

y¨=n200kndomnie(y-yn)mikn2)-100(y-yn)2)

Teraz nie musimy iść dalej: po prostu patrzymy na kierunek ogólnego przyspieszenia:

wynik={północJeśli y¨<0 i |y¨|>|x¨|południeJeśli y¨>0 i |y¨|>|x¨|ZachódJeśli x¨<0 i |x¨|>|y¨|WschódJeśli x¨>0 i |x¨|>|y¨|ŻadenJeśli |y¨|=|x¨|

I tak po prostu zjednoczyliśmy monety i boty. Gdzie jest moja Nagroda Nobla?


5
Twoja nagroda Nobla została utracona na poczcie, ale zamiast tego moglibyśmy ci dać nagrodę Emmy
Redwolf Programs

1
Wygląda na to, że fizyka zaczyna zdobywać popularność w tym wyzwaniu. :-RE. I oczywiście jestem bardzo ciekawy, jak dobrze sobie poradzi.
Ramillies,

1
(Nawiasem mówiąc, mogłeś uniknąć kłopotów z równaniami Eulera-Lagrange'a, ponieważ sprowadzają się one do dobrze znanego faktu, że F = c_me a = - grad U :—).)
Ramillies

@Ramillies Meh, fajniej było robić to w ten sposób: D
Beta Decay

1
Czy na pewno chcesz używać k = monet innego / swoich monet? Zaczynasz bez monet ... a wszędzie z NaN, nie ma zbyt wielu szans na ich zdobycie.
Ramillies,

8

Złotowłosa, 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
}

Wypróbuj online!

Po prostu blokuje się na miejscu złotej monety i podchodzi do niej za każdym razem. (Dzięki botowi „B33-L1N3” @ Mayube dla oryginalnego kodu, którego używał, choć prawie nic z niego nie zostało.)


To całkiem niezły, prosty bot. Lubię to.
Programy Redwolf

2
Nawiasem mówiąc, używam tego bota jako testu dla mojego kontrolera (:
Programy Redwolf

8

Algorytm uczenia się trzeciej generacji | 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)];
}

Wypróbuj online!

Po kilku pokoleniach uczenia ten bot nauczył się, że opuszczenie areny jest złe


O Boże. Słyszałem, że nazywa się to „
Doborem

5
Gdzie jest drugi gen
Luis felipe De jesus Munoz

11
@LuisfelipeDejesusMunoz Opuścił arenę.
Jo.

To dobry bot do debugowania kontrolera
Redwolf Programs

3
Nawiasem mówiąc, arena zaczyna się od 0, więc powinna być arenaLength - 1. To zabiło twojego bota kilka razy dla wielu
Redwolf Programs

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

Wypróbuj online!

Ustawia linię dla najbliższej monety


Och, myślałem, że B33-L1N3 to jakiś numer modelu
Redwolf Programs

+1 za imię
Cain

let coins = ...Uncaught SyntaxError: Identifier 'coins' has already been declared
Noc 2

Usuńlet
Programy 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';
  }
}

Ten słyszał, że skraj areny to niebezpieczne miejsce. Nie znając strachu, niestrudzenie krąży po planszy zgodnie z ruchem wskazówek zegara, zaledwie kilka centymetrów od pewnej śmierci, która czeka za granicą, mając nadzieję, że żaden inny bot nie odważy się zbliżyć tak blisko krawędzi.


1
To nie skończyłoby się dobrze, gdyby stworzono kolejnego bota, który miał jeszcze 1 monetę i patrolował granicę w przeciwnym kierunku (:
Programy Redwolf

8
Zrobiłbym żart kontroli granicznej, ale pozostawiam to @BetaDecay
Redwolf Programs

5

Damacy, 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
}

Wypróbuj online!

Ostatni na dzień bot oparty na katamari, tym razem z odrobiną pamięci. Dzięki @BetaDecay za sugestię nazwy - zdecydowanie bardziej zabawna nazwa niż moja simplePredictorKatamari.

Próbuje dowiedzieć się, w jaki sposób boty się poruszyły w ostatniej turze, i na tej podstawie przewiduje, gdzie będą próbować się poruszać pod koniec tej tury (zakładając, że nadal będą się poruszać w tym samym kierunku).

(Podziękowania dla @ fəˈnɛtɪk, za zauważenie, że wywoływałem niewłaściwą nazwę funkcji w botNotes, oraz @ @ᗺᗺ za zauważenie błędu w kodzie podstawowym.)


Jest to prawdopodobnie jedyny w tej chwili, który może złapać innych poza szczęściem.
Cain

Czy botnoty nie powinny być „przechowywane”, a nie ustawione?
fəˈnɛtɪk

@ fəˈnɛtɪk Zobacz, już potrzebuje poprawki! :) Dzięki, poprawione teraz.
sundar

Powinieneś zastąpić aWt = 1w params aWti umieścić aWt = aWt || 1pod (To samo z bWt). Zapobiega to błędom.
Programy Redwolf,

5

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

Wszystkie monety (w tym te przechowywane przez inne boty) emitują odpychającą siłę w kierunku Protonbota. W oparciu o tę siłę, zwiększa prędkość i odbija się od ścian (odwraca się natychmiast po uderzeniu w granicę). Jeśli trafi obok bota lub monety, którą może zużyć, Silna siła nuklearna przejmuje kontrolę i porusza się, aby go pochłonąć, zrzucając przy tym całą prędkość.


Hmm, fizyka jądrowa zastosowana w poszukiwaniu skarbów? To bije Science Channel każdego dnia!
Redwolf Programs,

Trzeba wymienić sinz Math.sin, cosz Math.cos, i tak dalej
Redwolfie Programy

4

Nie tak ślepo JavaScript (Node.js)

Ważna uwaga: to podejście nie jest całkowicie moje i na które odpowiedziano w podobnym pytaniu . Głosuj również na tę odpowiedź.

Czy słyszałeś kiedyś o algorytmie A * znajdowania ścieżki? oto jest. Tworzy najlepszą ścieżkę od jednego punktu do mniej wartościowej monety (ponieważ wszyscy wybierają najcenniejsze, nikt nie wybiera mniej) i stara się nie kolidować z żadnym innym użytkownikiem.

Oczekuje następujących parametrów:

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

Może robię taki, który poluje na inne boty


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
Wow ... już algorytm odnajdywania ścieżek? Minęły tylko 3 godziny!
Programy Redwolf,

@RedwolfPrograms Jak już powiedziałem, jest kopiowany z innego podobnego wyzwania. Musiałem tylko dostosować go do tego.
Luis felipe De jesus Munoz

Moje algorytmy szukają najbezpieczniejszych monet.
fəˈnɛtɪk

4

Tchórz | Python 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)

Jeśli to możliwe, unikaj botów z większą ilością pieniędzy. W przeciwnym razie weź leżące wokół pieniądze.


To najbardziej podstawowy bot, który ma szansę wygrać
Redwolf Programs,

4

Wild Goose Chase Bot, JavaScript

Bot, który jest naprawdę dobry w unikaniu innych botów, ale bardzo źle zdobywa monety.


Algorytm:

  1. Jeśli nie ma sąsiadujących botów, nie zwracaj żadnych
  2. Inaczej:
    1. Nie zwracaj żadnej z losową szansą 1/500 szansy (ma to na celu zapobieganie patom).
    2. Określ, do których pól można bezpiecznie się przenieść (tj. W arenie i nie jest zajęty przez innego bota)
    3. Zwróć jeden losowo

Kod:

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

Wypróbuj online!

Uwaga do programów Redwolf:

Ten bot może powodować bardzo długie rundy. Podjąłem pewne swobody, aby zapobiec patom, ale nie sprawdziłem, czy faktycznie są skuteczne. Jeśli ten bot stanie się problemem podczas testowania, możesz go zdyskwalifikować.


Dziękuję za notatkę. Specjalista od ewakuacji ma szansę na zebranie wystarczającej ilości monet podczas ścigania
Programy Redwolf

Lubię to. To prawie jak przynęta na roboty myśliwskie
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
}

Wypróbuj online!

(Dzięki @ OMᗺ za wskazanie błędu w oryginalnym kodzie, na którym został oparty).

Stara się rosnąć poprzez „zjadanie” botów z mniejszą ilością monet niż ona sama. Jeśli nie jest to możliwe (nie ma takiego bota), to szuka najbliższej monety.

Ta wersja ma małe poprawki, aby (a) dać pierwszeństwo złotym monetom niż srebrnym - z ryzykiem, że poszukiwanie bardziej odległej złotej monety może skończyć się kosztem życia bota lub może prowadzić do pogoni za złotym głupcem (b) pominąć boty z 0 monet - nie musisz tracić czasu na pogoń za nimi.


Mądry myśliwy ... dobrze, że jest jeszcze lepiej!
Programy Redwolf,

@RedwolfPrograms Miejmy nadzieję, że tak! :)
Niedziela

Powinienem nazwać to Damacy;)
Beta Decay


4

Uprzejmy, niedowidzący pijany bot | 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
}

Chwieje się, zbierając pobliskie monety, ale co jakiś czas losowo zmienia kierunek. Robi, co w jego mocy, aby nie wpaść na nikogo, ale staje się ... wojowniczy ... kiedy się denerwuje. Z biegiem czasu ma tendencję do wytrzeźwienia.

Może potrzebować trochę debugowania, gdy kontroler jest w pełni gotowy, popracuję nad tym.


3
Hmm, podnosi poprzeczkę, a potem się upija
Redwolf Programs

4

Ważony ruch | 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";
}

Porusza się w kierunku, w którym przypisała najwyższą wartość, unikając zbiegania z krawędzi planszy.

Wartość jest obliczana jako taka:

  • Moneta = moc monety / odległość do monety
  • Bot = Różnica w sile botów / 2 * odległość do bota

1
Cóż, to wygląda jak całkiem niesamowity bot. Pamiętaj, aby sprawdzić kierunki, ponieważ byłaby to prawdziwa strata, jeśli bot był mistrzem uruchomiony z dala od monet (:
Redwolf Programy

Nadal. Muszę być miły, prawda?
Programy Redwolf

Cóż, opublikuj to! Zrekompensuje mniejsze, szybsze boty, które również istnieją w tej chwili w dużych ilościach.
Programy Redwolf

for(i=0;i<6;i++){w sumie jest tylko 5 monet, 1 złoty i 4 srebrne. Twoja pętla działa 6 razy od 0 do 5.
Noc 2

3

Blindy | JavaScript (Node.js)

To na pewno nie wygra, ale przynajmniej weźmie udział. Najpierw spróbuj wyzwania KoH. Sortuje monety i przechodzi do najbliższej. Nie szuka graczy, więc nie obchodzi go, czy zderzy się z innymi.

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
}

Hmm, może zadziałać, ponieważ inne boty będą przede wszystkim szukały złota, potencjalnie pozostawiając cię do zdobycia srebra bez walki
Redwolf Programs

3

Feudal Noble | JavaScript

Preferowany kolor: #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;
}

Ten feudalny szlachcic pozostaje w centrum pola i twierdzi, że jest to jego własny pałac. Zbiera dla siebie wszystko w centrum, ale wszystko na odległych farmach powinno mu przynosić chłopi. Oczywiście, jeśli w pałacu pojawi się zły, potężny wieśniak, szlachcic może uciec, by uratować mu życie, ale wróci, gdy tylko będzie bezpieczny!

Z biegiem czasu chłopi stają się coraz silniejsi. Zawodowi wojownicy i potężni bohaterowie zaczynają wyrastać z chłopstwa. Moc szlachcica wciąż się psuje. Stara się utrzymać swoje bogactwo i swój system feudalizmu tak długo, jak to możliwe. Ale w końcu nadszedł czas, aby zaakceptować swoją wiarę, powinien zaakceptować, że ludzie nie chcą już feudalizmu. To dzień, w którym feudalny szlachcic porzuca wszystko, nie ucieka już przed potężnymi chłopami i zostaje zabity przez jednego z nich.


2

Bot Quantum Gnat | 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
}

Ten irytujący bot próbuje omijać najsilniejszego bota, nie dając się złapać, i ma niewielką szansę na przechodzenie między tymi, którzy próbują go upolować. Ma tendencję do przyciągania dwóch najpotężniejszych botów w bliskiej odległości ...;)


Jeśli nie może znaleźć odpowiedniego celu getTargetDirections(), zaczynają się dziać ciekawe rzeczy. (Jak na przykład rozbicie wszystkiego z powodu undefined has no property 0błędu.)
Ramillies,

2

Emerytowany agent ICE, JavaScript

Preferowany kolor: 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";
            }
        }
    }
}

Ten emerytowany agent ICE jest teraz na emeryturze i ma gorycz o ludzkości. W rezultacie wycofany ICE atakuje teraz najsłabszego bota, jednocześnie utrzymując wartość monety powyżej średniej (zgodnie z polityką ICE).


2

Chciwy Pościg | Haskell

Preferowany kolor: #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"

Wypróbuj online! *

Dość prosta strategia, wybiera pierwszą decyzję z:

  • jeśli są boty z mniejszą liczbą monet: wybierz najbliżej i zbliż się do niego
  • jeśli są monety: wybierz najbliżej i zbliż się do niej
  • domyślnie: zostań

Bot próbuje tylko złapać inne boty lub monety, nie troszcząc się o potencjalnie silniejsze boty, które mogą próbować je złapać.

* Naprawdę nie znam JavaScript, ale zrobiłem to z Google (może być niedokładne): wypróbuj online!


6
Zastanawiam się, jak on przetłumaczy haskell na js
Luis Felipe De

3
@LuisfelipeDejesusMunoz: Tak, ja też. Ale na szczęście nie jest to bardzo skomplikowany kod.
ბიმო

@LuisfelipeDejesusMunoz Wystarczy użyć Node.JS i process.open( child_process.spawnlub podobnego) z pewną analizą.
user202729,

@LuisfelipeDejesusMunoz: Próbowałem go przetłumaczyć i dodałem link, ale nie czuję się zbyt pewnie, pisząc JavaScript, więc może to być błąd.
ბიმო

4
@LuisfelipeDejesusMunoz Byłoby jedną rzeczą, gdyby był to program do nauki sztucznej inteligencji na 10 000 linii, ale myślę, że mogę sobie z tym poradzić (:
Programy Redwolf

1

Magnes na monety | 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";
}

Ten bot jest raczej głupi, kieruje się w stronę najbardziej znanych monet. Obejmuje to monety, których nie można zdobyć, ponieważ inne boty mają większą moc niż ona sama.


1

Agent ICE | 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";
            }
        }
    }
}

Jaki jest sens granicy, jeśli nie jest patrolowany? ICE porusza się wokół granicy przeciwnie do ruchu wskazówek zegara, zbierając boty, które zejdą mu na ścieżkę.

Zanim będzie to możliwe, musi najpierw móc zjeść innych botów. Z tego powodu ICE utrzymuje swoje monety powyżej średniej dla wszystkich botów.

Gwarantuje kraść dzieciom ich rodziców ™


Byłoby to bardziej zabawne, gdyby nie było tak istotne
Don Thousand

1

X oznacza miejsce | 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 oznacza miejsce, więc całe złoto musi znajdować się na osi x, prawda? Mój bot tworzy linię dla linii y = 0, a następnie zostaje tam, poruszając się losowo.


Hę, naprawdę interesująca metoda
Redwolf Programs


1
Biorąc pod uwagę fakt The arena starts at (0,0) in the upper left corner, czy jesteś pewien, że chcesz przejść south, aby dostać się y=0?
AdmBorkBork

@AdmBorkBork Dzięki, mogło być źle
Beta Decay

1

ognisty Ptak

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

Całkowicie odnowiony, aby był bardziej zabójczy niż wcześniej (:


2
Mój absolutny przegrany bota
Redwolf Programs,

Nie
atakuje

Och, przepraszam, źle zrozumiałem
rozpad

1

A-Path-y | JavaScript

Preferowany kolor tego bota to #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);
}

Ten bot używa funkcji wyszukiwania ścieżek w połączeniu z mapą celowości komórek, aby uniknąć botów, które mogłyby nas zabić, szukać monet, które są blisko, a nie pułapek i są najmniej ryzykowne.

Nie wydaje się być pretendentem do zwycięskiego miejsca, ale zachowuje swoją własną i będzie żył pod koniec meczu, jeśli przeżyje początkową walkę w zwarciu.

Bot ma teraz strategię od późnej do późnej fazy gry, która ignoruje monety, do których nie może dotrzeć przed innymi botami, a jeśli nie może dotrzeć do żadnej monety, wówczas przechodzi do najbliższej komórki, która jest najdalej od wszystkich innych botów, które są silniejsze od niej samej.

Teraz ma szansę wygrać.

Uwaga, przykro mi z powodu kiepskiego kodu, automatycznie przekonwertowałem go z Javy


Pamiętaj, aby usunąć wszelkie błędy i / lub aktualizacje wkrótce, za 18 godzin!
Programy Redwolf

@RedwolfPrograms Czy zauważyłeś błąd? jeśli tak, proszę dać mi znać, żebym mógł to poprawić. Dzięki
Moogie

Nie, ale nigdy nie wiadomo. Tylko pamiętaj, aby dokładnie sprawdzić, ponieważ widziałem wiele botów stracić ze względu na jeden zły numer, lub niewłaściwej funkcji lub błędnie więcej razy, niż mogę liczyć
Redwolf Programy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.