KOTH: Wszyscy kochają tokeny

24

W tej grze dwóch graczy rywalizuje o zjedzenie żetonów o największej liczbie punktów, ale jest pewien zwrot akcji! Zjedzenie wielu żetonów w jednym rzędzie tego samego koloru daje ciągle rosnącą premię, ale uważaj, bo przeciwnik pokrzyżuje twoje plany, jedząc żetony, które chcesz, zanim będziesz mógł!

Zasady:

  • 1 kontra 1
  • tablica n na n (losowy rozmiar od 5 x 5 do 15 x 15)
  • Ty i twój przeciwnik odrodzicie się w tej samej losowej komórce
  • Na całej planszy będą losowo generowane liczby w niektórych komórkach o wartości od 1-3
  • Wygenerowane zostaną 2 * (szerokość planszy) żetony, ale mogą być zastąpienia, więc może być ich mniej przypadkowo.
  • Każda liczba będzie miała jeden z 3 kolorów: czerwony, zielony lub niebieski, w formacie szesnastkowym RGB
  • W każdej rundzie gracz 1 porusza się, a plansza jest aktualizowana, następnie gracz 2 porusza się, a plansza jest aktualizowana. Aby każdy gracz mógł skutecznie powiedzieć, jaki ruch wykonał poprzedni gracz, na podstawie zmiany stanu planszy. Trwa to do końca gry, jak opisano później.
  • Masz 6 możliwych akcji dla tury: W GÓRĘ, W PRAWO, W DÓŁ, ​​W LEWO, JEDZ i PODAJ
  • 4 polecenia ruchu są zrozumiałe i MOŻNA przekazać swoją turę. Jeśli zwrócisz bezsensowny ruch, założymy, że chciałeś spasować. Jeśli spróbujesz zejść z krawędzi planszy, nie poruszysz się. Krawędzie się nie zawijają.
  • EAT zużywa numer, który aktualnie znajdujesz się w tym samym miejscu, co
  • Zyskujesz tyle punktów, ile zużywasz
  • Jeśli zjesz 2 liczby w jednym rzędzie tego samego koloru, otrzymasz +1
  • Jeśli zjesz 3 liczby w jednym rzędzie tego samego koloru, otrzymasz +2
  • Jeśli zjesz liczbę m w rzędzie tego samego koloru, otrzymasz + (m-1)
  • Te bonusy są dodawane kumulatywnie, więc zdobycie m liczb z rzędu prowadzi do m * (m-1) / 2 całkowitej premii do czasu, gdy zjesz inny kolor.
  • Warunki zakończenia gry:
    • Wszystkie liczby są zużywane
    • Minęły 4 * (szerokość planszy) tury bez skutecznego jedzenia (po prostu mówiąc „JEŚĆ” bez żetonu, gdzie się nie liczysz) występującego przez któregokolwiek gracza (dowolny żeton jest osiągalny w 2 * (szerokość) przesuwa się, więc ta granica zostanie przekroczona tylko wtedy, gdy obaj gracze nie mają na myśli jednego żetonu celu)
  • Twoja sztuczna inteligencja powinna zająć mniej niż sekundę, aby wykonać ruch, w przeciwnym razie PASS zostanie przyjęte jako twój wybór.

Turniej będzie odbywać się w trybie rundy z dużą liczbą rund, powiedzmy 100 lub 1000. Generowana jest losowa plansza, a każda zamówiona para różnych graczy jest prowadzona na tej planszy. Po zakończeniu turnieju uszeregujemy ludzi według ich całkowitego wyniku. Więc nawet jeśli jesteś graczem 2 w grze, Twoim celem jest zdobycie jak największej liczby punktów.

Zgłoszenie AI: Językiem obsługiwanym przez mój kontroler jest JavaScript. Dozwolone jest wielokrotne przesyłanie. Każdy przesyła konstruktor dla takiego obiektu:

function (player1) {
    this.yourMove = function (b) {
        return "MOVE";
    }
}

Dane wejściowe player1to boolean mówiący, czy jesteś graczem 1, czy nie. Twój konstruktor musi mieć yourMovefunkcję, ale może mieć także dowolną liczbę dodatkowych funkcji lub wartości. Nie definiuj żadnych globalnych zmiennych, po prostu umieść je jako zmienne na swoim obiekcie. Nowa wersja twojego obiektu zostanie utworzona na początku każdego meczu i yourMovebędzie do niego wywoływana, z bieżącą tablicą jako wejściem, w każdej twojej turze i powinna zwrócić prawidłowy ruch.

b, dane wejściowe do yourMove, są kopią bieżącej planszy, oto konstruktory z przykładowymi danymi wejściowymi, chociaż nie można ich nazwać samemu:

function token(color, points) {
    this.color = color; //"#FF0000"
    this.points = points; //5
}

function player(pos, score, colorBonus, lastColor) {
    this.pos = pos; //[5, 5]
    this.score = score; //9
    this.colorBonus = colorBonus; //i.e. 2 if you just ate 3 blue tokens in a row
                                  //0 if you just ate two different colors.
    this.lastColor = lastColor; //"#00FF00", is "#000000" at start
}

function board(player1, player2, tokens) {
    this.player1 = player1; //new player([5, 5], 9, 2, "#00FF00")
    this.player2 = player2; //new player([5, 5], 9, 2, "#00FF00")
    this.tokens = tokens; //[[new token("#0000FF", 5), false],
                      // [new token("#0000FF", 5), false]]
}

Tablica tokenów ma wartość „false” dla dowolnych pustych kwadratów, a tokeny [a] [b] to token o numerze x = a, y = b, numerowany od lewego górnego rogu.

Kontroler: Oto link do kontrolera w GitHub. Jest to plik html, który możesz uruchomić, aby zobaczyć, jak działa gra i round-robin. Zawiera dwa AI, losowy, który porusza się w losowym kierunku w każdej turze, ale zjada żetony w swojej pozycji, oraz naiwny algorytm, który wybiera najbliższy token, który daje najwięcej punktów. Dodam każdą AI w miarę jej przesyłania.

Poniżej znajduje się fragment, który pozwala uruchomić kontroler na domyślnej sztucznej inteligencji. Obecne AI:

  • KindaRandomAI
  • NaiveAI
  • MirrorBot
  • HungryBot

Fricative Melon
źródło
12
Tak, KOTH! To było wieczne od ostatniego.
TheNumberOne
2
Zgadzam się, uwielbiam dobrą KOTĘ i wydaje się to być świetną przesłanką. Jestem trochę zielony do js, ​​jak można zachować stan gry między ruchami, jeśli nie możemy zapisać wyników w obiekcie naszego gracza?
DoctorHeckle,
Czy szerokość deski jest przekazywana gdziekolwiek do funkcji?
TheNumberOne
@BentNeeHumor Tak, funkcja, która przyjmuje wartość player1logiczną, jest konstruktorem dla twojej sztucznej inteligencji, która będzie miała yourMovefunkcję , która pobierze bieżącą płytę jako dane wejściowe b.
Fricative Melon
1
@DylanSp Czasami nie są one dozwolone ze względu na możliwości zmowy, ale w tym przypadku zmowa przyniosłaby minimalne korzyści, więc pozwolę na wielokrotne przesyłanie.
Fricative Melon

Odpowiedzi:

4

HungryBot

Wykorzystuje system punktowy, aby zwiększyć wagę realizacji każdego tokena. Uwzględnia różnorodne czynniki i dokonuje ich ponownej oceny w każdej turze, aby zapewnić najlepszą strategię.

function hungryBot(first) {
  // Set up "self"
  var self = this;

  // Determine player order
  this.player = -(first - 2);
  this.enemy = first + 1;

  // Action associative array
  this.actions = ['EAT', 'LEFT', 'RIGHT', 'UP', 'DOWN'];

  //Logic handler
  this.yourMove = function(board) {
    // Determine player object
    var player = board['player' + self.player];
    var enemy = board['player' + self.enemy];

    // Point value action grid
    var actions = [0, 0, 0, 0, 0]; // Associative with "this.actions"

    // Board dimensions
    var size = board.tokens.length;
    var maxDist = size * 2;

    // Colors remaining
    var colors = {
      '#FF0000': 0,
      '#00FF00': 0,
      '#0000FF': 0
    };

    // Averaged value weight
    var average = [0, 0];

    // Total points
    var points = 0;

    // Token holder
    var tokens = [];

    // Token parser
    for (var i = 0, x = 0, y = 0; i < size * size; i += 1, x = i % size, y = i / size | 0) {
      if (!board.tokens[x][y]) {
        continue;
      } else {
        var token = {};
        token.points = board.tokens[x][y].points;
        token.color = board.tokens[x][y].color;
        token.x = x - player.pos[0];
        token.y = y - player.pos[1];
        token.distX = Math.abs(token.x);
        token.distY = Math.abs(token.y);
        token.dist = token.distX + token.distY;
        token.distE = Math.abs(x - enemy.pos[0]) + Math.abs(y - enemy.pos[1]);
        token.value = -token.points - (player.colorBonus + 1) * (token.color == player.lastColor) * ((token.dist == 0) + 1) * 1.618 - (enemy.colorBonus + 1) * (token.color == enemy.lastColor);
        tokens.push(token);
        colors[token.color] += 1;
        points += token.points;
        average[0] += x * token.points;
        average[1] += y * token.points;
      }
    }

    // Determine actual average
    average[0] = average[0] / points | 0;
    average[1] = average[1] / points | 0;

    // Pick best token
    var best = 0;

    // Calculate point values of tokens
    for (i = 0; i < tokens.length; i++) {
      var token = tokens[i];
      // Add remaining numbers of tokens of color as factor
      token.value -= (colors[token.color] / tokens.length) * 1.618;
      // Subtract distance as a factor
      token.value += token.dist;
      // Add distance to average to value
      token.value += (Math.abs(average[0] - (token.x + player.pos[0])) + Math.abs(average[1] - (token.y + player.pos[1]))) / Math.sqrt(2);
      // Consider them higher value if we are closer, and lower if they are
      token.value += ((token.dist - token.distE) / (token.dist + token.distE + 0.001)) * token.dist;
      // Don't go for it if enemy is already there
      token.value += (token.distE == 0 && token.dist > 0) * 100;

      if (tokens[best].value > tokens[i].value || (tokens[best].value === tokens[i].value && Math.round(Math.random()))) {
        best = i;
      }
    }

    // Set token to best token
    var token = tokens[best];

    // What to respond with
    var response = 'PASS';

    // Find best action to get token
    if (token.dist == 0) {
      response = 'EAT'; // We're on the token
    } else if (token.distX >= token.distY) { // Token is more horizontal
      if (token.x < 0) { // Token is left
        response = 'LEFT';
      } else if (token.x > 0) { // Token is right
        response = 'RIGHT';
      }
    } else if (token.distX < token.distY) { // Token is more vertical
      if (token.y < 0) { // Token is above
        response = 'UP';
      } else if (token.y > 0) { // Token is below
        response = 'DOWN';
      }
    }

    // Return response
    return response;
  }
};
Mwr247
źródło
Czy jesteś programistą Python?
CalculatorFeline,
@CatsAreFluffy Nie bardzo ...?
Mwr247,
Po prostu myślałem, że jesteś, ponieważ self:)
CalculatorFeline
Dlaczego warto korzystać self? Nie thiswystarczy?
Conor O'Brien
2

ŚCIEŻKA bot

Skrót oznacza Pathfinding And Tree Heuristics Bot

EDYCJA: Na razie oto rankingi dla AI, z punktami

  1. HungryBot (6422)
  2. PATH bot (4591)
  3. NaiveAI (3811)
  4. KindaRandomAI (618)
  5. MirrorBot (193)
  6. LazyBot (25)

Link do pełnego kontrolera na github

Opis: Podobnie jak NaiveAI, ten bot znajduje najbliższy token, który da mu najwięcej punktów. Symuluje jednak wyniki każdego z ruchów nawet 6 razy.

Uzasadnienie: Ponieważ NaiveAI jest już całkiem dobry, pomyślałem, że poprawiłbym to. Nie patrząc najpierw na kod (duży błąd).

Uderzenia: Wszystkie oprócz HungryBot Przegrywa
z: Brak, z wyjątkiem HungryBot

Problemy:

  • Nie można symulować zwiększonej serii
  • Zawiesza się podczas obliczania najlepszego tokena
  • Może się teleportować

Nadal nie wiem, dlaczego to się teleportowało, ale naprawiłem to. Stary film tutaj: https://youtu.be/BIhSKycF9iA

Pełny kod:

pathBot = function (player1)
{
    this.pathNode = function(pos,ppt,parents,par)
    {
        this.pos = pos;this.ppt = ppt;this.parents = parents;this.par=par;
        this.childs=[];
    }
    this.addChildren = function (pn,children)
    {
        pn.childs=[];
        for(var i=0; i<children.length; i=i+1)
        {
            if(pn.parents.indexOf(children[i].pos)==-1&&pn.pos!=children[i].pos)
                pn.childs.push(
                    new this.pathNode(
                        children[i].pos,
                        children[i].ppt*pn.ppt,
                        pn.parents.concat([pn.pos]),
                        pn
                    )
                );
        }
    }
    this.orderTokensByPPT = function(b,pos){
        var tokens = [];
        for(var y=0; y<b.tokens.length; y=y+1)
        {
            for(var x=0; x<b.tokens[y].length; x=x+1)
            {
                var tok = b.tokens[y][x];
                if(tok)
                {
                    tokens.push(
                        new this.pathNode(
                            [y,x],
                            (tok.points+(tok.color==this.color ? this.streak : 0)) / this.lenOfMovesTo(pos,[y,x]),
                            [],
                            undefined
                        )
                    );
                }
            }
        }
        tokens.sort(function(a,b){
            return b.ppt - a.ppt;
        });
        return tokens;
    }
    this.lenOfMovesTo = function(cur,pos)
    {
        return Math.abs(cur[0]-pos[0])+Math.abs(cur[1]-pos[1])+1;
    }
    this.startAndGoalToCommand = function (start, goal) {
        var diff = [goal[0] - start[0], goal[1] - start[1]];
        if (diff[0] > 0) { return "RIGHT"; }
        else if (diff[1] > 0) { return "DOWN"; }
        else if (diff[1] < 0) { return "UP"; }
        else if (diff[0] < 0) { return "LEFT"; }
        else { return "EAT"; }
    }
    this.color = 0;
    this.streak = 0;
    this.eatTok = function(b)
    {
        if(b.tokens[this.me.pos[0]][this.me.pos[1]].color==this.color)
        {
            this.streak++;
        }
        else{
            this.streak = 0;
            this.color = b.tokens[this.me.pos[0]][this.me.pos[1]].color;
        }
        this.bestToken = false;
        return "EAT";
    }

    this.recurLen = 6;
    this.include = 4;
    this.recurDown = function(b,pn,level)
    {
        if(level==0) return pn;
        this.addChildren(pn,this.orderTokensByPPT(b,pn.pos));
        var newChilds = [];
        for(var i=0; i<pn.childs.length&&i<this.include; i=i+1)
        {
            newChilds.push(this.recurDown(b,pn.childs[i],level-1));
        }
        pn.childs = newChilds;
        return pn;
    }
    this.findMax = function(pn)
    {
        if(pn.childs)
        {
            var maxList = [];
            for(var i=0; i<pn.childs.length; i=i+1)
                maxList.push(this.findMax(pn.childs[i]));
            maxList.sort(
                function(a,b)
                {
                    return b.ppt-a.ppt;
                }
            );
            return maxList[0];
        }
        return pn;
    }
    this.findMaxList = function(pnList)
    {
        for(var i=0; i<pnList.lenght; i=i+1)
        {
            pnList[i] = this.findMax(pnList[i]);
        }
        pnList.sort(function(a,b){return b.ppt-a.ppt;});
        return pnList[0];
    }
    this.bestToken=false;
    this.yourMove = function(b){
        this.op = player1 ? b.player2 : b.player1;
        this.me = player1 ? b.player1 : b.player2;
        if(this.bestToken)
        {
            if(b.tokens[this.bestToken.pos[0]][this.bestToken.pos[1]]==undefined)
                this.bestToken = false;
        }
        if(!this.bestToken)
        {
            var paths = this.orderTokensByPPT(b,this.me.pos);
            for(var i=0; i<paths.length; i++)
            {
                paths[i] = this.recurDown(b,paths[i],this.recurLen);
            }
            var max = this.findMaxList(paths);
            while(max.par)
            {
                max = max.par;
            }
            this.bestToken = max;
        }
        var move = this.startAndGoalToCommand(this.me.pos,this.bestToken.pos);
        if(move=="EAT") return this.eatTok(b);
        else return move;
    }
}
niebieski
źródło
SLaNTbot spowalnia prędkość skręcania i zjada 15% mojego procesora ... D: EDYCJA: A także nic nie jesz?
Mwr247
@ Mwr247 prędkość, tak, modeluje ~ 2500 możliwości każdego ticka. Ale jeśli chodzi o jedzenie, nie wiem dokładnie dlaczego. Tak jak powiedziałem w pytaniu, po prostu się teleportuje (czyli porusza wiele pól w 1 turze) i siedzi tam, nic nie robiąc. Ostrzegam przed powrotem i wydaje się, że za każdym razem wydaje właściwe instrukcje.
Niebieski
Może to: „Twoja sztuczna inteligencja powinna zająć mniej niż sekundę, aby wykonać ruch, w przeciwnym razie PASS zostanie uznany za twój wybór”. Nie przeczytałem kontrolera, ale jeśli zajmuje on sekundę, to czy przyjmuje PASS?
Mwr247
@ Mwr247 Zajmę się tym, ale wydaje się mało prawdopodobne, biorąc pod uwagę, że zajęło mi to <1 sekundę (a przynajmniej tak mi się zdawało) na moim komputerze. Mimo to nigdy nie boli patrzeć. Dziękuję Ci!
Niebieski
@ Mwr247 Po kilku kolejnych testach to nie wszystko. Podejmuje decyzje prawie tak szybko (przynajmniej dla mnie) jak NaiveAi. Ponadto istnieje większe prawdopodobieństwo teleportacji na dużych mapach
niebieski
1

NaiveAI

Zaczynając od r=0, spójrz na wszystkie tokeny w odległości taksówki rod twojej pozycji. Jeśli są, wybierz taki, który zapewni najwyższy wynik, jeśli go teraz uzyskasz. W przeciwnym razie zwiększ ro 1 i spróbuj ponownie.

naiveAI = function(player1) {
  this.player1 = player1;
  this.yourMove = function(b) {
    var me;
    if (this.player1) {
      me = b.player1;
    } else {
      me = b.player2;
    }
    var d = 0;
    var tokenP;
    while (tokenP == undefined) {
      var arr = this.findTokensAtDistance(me.pos, d)
      tokenP = this.findBestToken(arr, b.tokens, me);
      d += 1;
    }
    return this.startAndGoalToCommand(me.pos, tokenP);
  }
  this.findTokensAtDistance = function(p, d) {
    if (d == 0) {
      return [
        [p[0], p[1]]
      ];
    }
    var myArr = [];
    for (i = 0; i <= d; i++) {
      myArr[i] = [i, d - i];
    }
    var mySecArr = [];
    for (i = 0; i <= d; i++) {
      mySecArr[i] = [myArr[i][0] + p[0], myArr[i][1] + p[1]];
    }
    mySecArr[mySecArr.length] = [myArr[0][0] + p[0], -myArr[0][1] + p[1]];
    for (i = 1; i < myArr.length - 1; i++) {
      mySecArr[mySecArr.length] = [-myArr[i][0] + p[0], myArr[i][1] + p[1]]
      mySecArr[mySecArr.length] = [myArr[i][0] + p[0], -myArr[i][1] + p[1]]
      mySecArr[mySecArr.length] = [-myArr[i][0] + p[0], -myArr[i][1] + p[1]]
    }
    mySecArr[mySecArr.length] = [-myArr[myArr.length - 1][0] + p[0], myArr[myArr.length - 1][1] + p[1]];
    return mySecArr;
  }
  this.findBestToken = function(arr, t, player) {
    var tokenPos;
    for (i = 0; i < arr.length; i++) {
      if (arr[i][0] >= 0 && arr[i][0] < t.length && arr[i][1] >= 0 && arr[i][1] < t.length) {
        if (t[arr[i][0]][arr[i][1]] != false && ((tokenPos == undefined) || (this.tokenScore(player, t[arr[i][0]][arr[i][1]]) > this.tokenScore(player, t[tokenPos[0]][tokenPos[1]])))) {
          tokenPos = [arr[i][0],
            [arr[i][1]]
          ];
        }
      }
    }
    return tokenPos;
  }
  this.tokenScore = function(player, token) {
    if (player.lastColor == token.color) {
      return player.colorBonus + 1 + token.points;
    } else {
      return token.points;
    }
  }
  this.startAndGoalToCommand = function(start, goal) {
    var diff = [goal[0] - start[0], goal[1] - start[1]];
    if (diff[0] > 0) {
      return "RIGHT";
    } else if (diff[1] > 0) {
      return "DOWN";
    } else if (diff[1] < 0) {
      return "UP";
    } else if (diff[0] < 0) {
      return "LEFT";
    } else {
      return "EAT";
    }
  }
}
Fricative Melon
źródło
1

KindaRandomAI

W każdej turze wykonaj następujące czynności: Jeśli na twojej pozycji znajduje się token, „Zjedz”. W przeciwnym razie poruszaj się w losowo wykonalnym kierunku, tj. Jeśli jesteś na lewej krawędzi, nie mów „LEWO”.

kindaRandomAI = function(player1) {
    this.player1 = player1;
    this.yourMove = function(b) {
        var me;
        if (this.player1) {
            me = b.player1;
        } else {
            me = b.player2;
        }
        if (b.tokens[me.pos[0]][me.pos[1]] != false) {
            return "EAT";
        } else {
            var dirs = this.getViableDirections(b, me.pos);
            var rand = Math.floor(Math.random() * dirs.length);
            return dirs[rand];
        }
    }
    this.getViableDirections = function(b, p) {
        var dirs = [];
        if (p[0] > 0) {
            dirs.push("LEFT");
        }
        if (p[1] > 0) {
            dirs.push("UP");
        }
        if (p[1] < b.tokens.length - 1) {
            dirs.push("DOWN");
        }
        if (p[0] < b.tokens.length - 1) {
            dirs.push("RIGHT");
        }
        return dirs;
    }
}
Fricative Melon
źródło
-1 nie do końca losowy
CalculatorFeline
Tak jest lepiej!
CalculatorFeline,
1

LazyBot

Zjada coś tylko, jeśli się odrodzi. To nie ma szans na wygraną, ale wyzwanie nie miało jednego z nich, więc dlaczego nie.

lazyBot = function (player1) {
    this.yourMove = function(b) {
        return "EAT";
    }
}
Bálint
źródło
1
Każdy koth ma EmoWolf ...
Niebieski,
3
@Blue To nie jest 100% emo, próbuje jeść.
Bálint,
1

MirrorBot

Należy nazwać „paszą armatnią”

Opis: Przenosi dokładne przeciwieństwo tego, co zrobił inny gracz

Uzasadnienie: Chciałem znów uzyskać wygodne programowanie w JS. To nie powinno wygrać

Pobije: Nikt

Stracą: Wszyscy

function mirror(player1) {
    this.hasStarted=false;
    this.player1 = player1;
    this.opl=[0,0];
    this.yourMove = function(b){
        this.op = this.player1 ? b.player2.pos : b.player1.pos;
        out = "EAT";
        console.log(this.op);
        console.log(this.opl);
        if(this.hasStarted){
            if(this.opl[0] < this.op[0]) out = "RIGHT";
            if(this.opl[0] > this.op[0]) out = "LEFT";
            if(this.opl[1] < this.op[1]) out = "UP";
            if(this.opl[1] > this.op[1]) out = "DOWN";
        }
        this.opl = [this.op[0],this.op[1]];
        this.hasStarted = true;
        return out;
    }
}
niebieski
źródło
Z twoim kodem jest kilka problemów. Prawa i lewa nie są przeciwne, a twoja funkcja funkcji yourMove nie jest poprawną składnią. Mój kod również był wcześniej uszkodzony, więc w trakcie znajdowania i rozwiązywania problemu w moim kodzie również go naprawiłem. Możesz spojrzeć na poprawiony kod w moim skrypcie.
Fricative Melon
@FricativeMelon Naprawiłem uszkodzoną definicję funkcji. Muszę odrzucić twierdzenie, że prawo nie jest odwrotne.
Niebieski,
0,0 to lewy górny róg, więc dodatni x jest prawy, a ujemny x - lewy. jeśli nowy x-pos ma większą wartość niż stary x-pos, drugi gracz przesunął się w prawo, więc powinieneś przejść w lewo i odwrotnie. Powinieneś także użyć var out = "EAT";zamiast out = "EAT";, ponieważ później definiuje zmienną globalną. Jeśli trochę się nie podoba, trzecia i czwarta linia nic nie robią i mogą być również usunięte, i opmogą być lokalną zmienną, jak outzamiast właściwości.
Fricative Melon
@FricativeMelon ah, rozumiem co mówisz. Zaktualizowałem kod. Dziękuję Ci!
Niebieski,
Wstawiłem twój nowy kod do skryptu i teraz działa. Nie pokonuje jednak RandomAI :(
Fricative Melon 7.04.16
0

OneTarget

Znajduje token, który da najwięcej punktów w jak najkrótszym czasie i przejdzie do tego. Ranga tokenów tego samego koloru jest nieco wyższa ze względu na efekt skumulowany.

function (player1) {
    this.yourMove = function (b) {
        var me = player1? b.player1: b.player2;
        var him= player1? b.player2: b.player1;
        var x = me.pos[0];
        var y = me.pos[1];
        var maxVal = -1;
        var maxX = 0;
        var maxY = 0;
        for(var i = 0;i < b.tokens.length;i++){
            for(var j = 0;j < b.tokens.length;j++){
                if(b.tokens[i][j]){
                    var dist = Math.abs(x-i) + Math.abs(y-j);
                    var val = this.valueOf(b.tokens[i][j]);
                    val /= (dist + 1);
                    if(val > maxVal){
                        maxVal = val;
                        maxX = i;
                        maxY = j;
                    }
                }
            }
        }
        if(maxY < y)
            return "UP";
        if(maxX < x)
            return "LEFT";
        if(maxY > y)
            return "DOWN";
        if(maxX > x)
            return "RIGHT";
        return "EAT";
    }
    this.valueOf = function(t){
        //how many points would it give you?
        return t.points + (this.lastColor == t.color? 2 * this.colorBonus + 1 : 0);
    }
}
MegaTom
źródło
0

QuantityPlayer

Wszystkim, którym zależy na QuantityPlayer, jest ilość kropek, które je, a nie ich wartość lub kolor. Wie, że chociaż wszystkie kropki są różne, należy je traktować tak samo.

QuantityBot = function(playernum) {

this.dist = function(token) {
    return (Math.abs(token[0])+Math.abs(token[1]))
}

this.yourMove = function(game_board) {

    board_size = game_board.tokens.length
    board_area = board_size * board_size
    fete = board_size = size * 2

    token_list = []
    count = curr_x = curr_y = 0
    while(count < board_area) {
        if(game_board.tokens[x][y]) {
        token_list.push([x-player.pos[0],y-player.pos[1]])
        }
        count++; x = count % board_size; y = Math.floor(count / size)
    }

    closest_token = token_list[0]
    count = 1
    while(count < token_list.length) {
        curr_token = token_list[count]
        if(dist(curr_token) < dist(closest_token)){closest_token = curr_token}

        count++
    }

    if(dist(closest_token)==0){return 'EAT'}
    else{
    if(closest_token[0] >= closest_token[1]) {if(closest_token[0]<0) {return 'LEFT'} {return 'RIGHT'}}
    else{if(closest_token[1]<0) {return 'UP'} {return 'DOWN'}}
    }

}

}
Benjamin Philippe
źródło