KOTH: Todo mundo adora fichas

24

Neste jogo, dois jogadores competem para comer o máximo de pontos em fichas, mas há uma reviravolta! Comer vários tokens em uma fileira da mesma cor dá um bônus cada vez maior, mas cuidado, ou seu oponente frustrará seus planos comendo os tokens que você deseja antes que você possa!

Regras:

  • 1 versus 1
  • n por n tabuleiro (tamanho aleatório entre 5x5 e 15x15)
  • Você e seu oponente aparecerão na mesma célula aleatória
  • Em todo o quadro serão gerados aleatoriamente números em algumas células com valores que variam de 1-3
  • Serão gerados 2 * (a largura da placa) tokens, mas pode haver substituições, portanto, pode haver menos por acaso.
  • Cada número terá uma de três cores: vermelho, verde ou azul, no formato RGB hexadecimal
  • A cada rodada, o jogador 1 se move e o tabuleiro é atualizado, depois o jogador 2 se move e o tabuleiro é atualizado. Assim, cada jogador pode efetivamente dizer qual jogada o jogador anterior fez com base na mudança no estado do tabuleiro. Isso continua até o jogo terminar, conforme descrito mais adiante.
  • Você tem 6 ações possíveis para um turno: CIMA, DIREITA, BAIXO, ESQUERDA, COMA E PASSA
  • Os 4 comandos de movimento são auto-explicativos e você PODE passar a sua vez. Se você retornar uma jogada sem sentido, assumiremos que você quis dizer passar. Se você tentar sair da borda do tabuleiro, não o fará. As bordas não se enrolam.
  • O EAT consome o número em que você está atualmente no mesmo espaço que
  • Você ganha tantos pontos quanto o número que consome
  • Se você comer 2 números consecutivos da mesma cor, receberá +1
  • Se você comer 3 números seguidos da mesma cor, receberá +2
  • Se você comer m números consecutivos da mesma cor, obterá + (m-1)
  • Esses bônus são adicionados cumulativamente, portanto, obter m números seguidos leva a m * (m-1) / 2 no bônus total quando você come uma cor diferente.
  • Condições finais do jogo:
    • Todos os números são consumidos
    • Os giros de 4 * (a largura do tabuleiro) se passaram sem uma alimentação efetiva (apenas dizendo "COMA" sem token onde você não conta) ocorrendo por qualquer jogador (qualquer token é alcançável em 2 * (a largura) movimentos, então esse limite só será superado se os dois jogadores não tiverem um símbolo de alvo único em mente)
  • Sua IA deve levar menos de um segundo para fazer uma jogada, caso contrário, o PASS será assumido como sua escolha.

O torneio será de rodízio com um grande número de rodadas, digamos 100 ou 1000. Um tabuleiro aleatório é gerado e cada par ordenado de jogadores diferentes é executado nesse tabuleiro. Após o término do torneio, classificaremos as pessoas pela pontuação total. Portanto, mesmo se você for o jogador 2 de um jogo, seu objetivo ainda é conseguir o máximo de pontos possível.

Envio de AI: o idioma que meu controlador suporta é Javascript. Vários envios são permitidos. Todo mundo envia um construtor para um objeto como este:

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

A entrada player1é um booleano dizendo se você é o jogador 1 ou não. Seu construtor deve ter a yourMovefunção, mas também pode ter qualquer número de funções ou valores adicionais. Não defina nenhuma variável global, apenas coloque-a como variável em seu objeto. Uma nova versão do seu objeto será criada no início de cada partida e yourMoveserá convocada para ele, com o quadro atual como entrada, em cada um dos seus turnos, e deve retornar uma jogada válida.

b, a entrada para yourMove, é uma cópia da placa atual, eis os construtores, com exemplos de entrada, embora você não possa chamá-los:

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

A matriz de tokens tem "false" para todos os quadrados vazios, e os tokens [a] [b] são o token em x = a, y = b, numerados a partir do canto superior esquerdo.

Controlador: Aqui está um link para o controlador no GitHub. É um arquivo html que você pode executar para ver como o jogo e o round-robin funcionam, e vem com duas IAs, uma aleatória que se move em uma direção aleatória a cada turno, mas consome tokens em sua posição e um algoritmo ingênuo que vai para o token mais próximo que dá mais pontos. Adicionarei em cada AI conforme ele for enviado.

Abaixo está um trecho que permite executar o controlador no AI padrão. AIs atuais:

  • KindaRandomAI
  • NaiveAI
  • MirrorBot
  • HungryBot

Melão Fricativo
fonte
12
Yay, um KOTH! Faz sempre desde o último.
TheNumberOne
2
Concordo, eu me amo um bom KOTH e isso parece ser uma grande premissa. Eu sou um pouco verde para js, como um jogo persiste entre movimentos se não podemos salvar resultados dentro do objeto jogador?
precisa
A largura da placa passou para algum lugar da função?
TheNumberOne
@BentNeeHumor Sim, a função que recebe o player1booleano é o construtor da sua IA, que terá uma yourMovefunção que recebe a placa atual como entrada, como b.
Fricative Melon
11
@DylanSp Às vezes, eles não são permitidos devido a possibilidades de conluio, mas, nesse caso, o conluio traria benefícios mínimos, por isso permitirei vários envios.
Fricative Melon

Respostas:

4

HungryBot

Usa um sistema de pontos para adicionar peso ao valor de buscar cada token. Usa uma variedade de fatores diferentes em sua consideração e os reavalia a cada turno para garantir que segue a melhor estratégia.

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
fonte
Você é um programador Python?
CalculatorFeline
@CatsAreFluffy Not really ...?
Mwr247
Apenas pensei que você fosse porque self:)
CalculatorFeline
Por que usar self? Não é thissuficiente?
Conor O'Brien
2

PATH bot

Sigla significa Pathfinding And Tree Heuristics Bot

EDIT: A partir de agora, aqui estão as classificações para as IAs, com os pontos

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

Link para o controlador completo no github

Descrição: como o NaiveAI, este bot encontra o token mais próximo que lhe dará mais pontos. No entanto, também simula os resultados de cada um de seus movimentos, até 6 vezes.

Justificativa: Como o NaiveAI já é muito bom, eu acho que o tornaria melhor. Sem olhar para o código primeiro (grande erro).

Batimentos: Todos, exceto o HungryBot,
perde para: Nenhum, exceto o HungryBot

Problemas:

  • Não é possível simular um aumento na sequência
  • Trava ao calcular o melhor token
  • Pode se teletransportar

Ainda não sei por que estava se teletransportando, mas consertei. Vídeo antigo aqui: https://youtu.be/BIhSKycF9iA

Código completo:

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;
    }
}
Azul
fonte
O SLaNTbot está diminuindo a velocidade de rotação e consumindo 15% da minha CPU ... D: EDIT: E também não está comendo nada?
precisa saber é o seguinte
@ Mwr247 a velocidade, sim, modela ~ 2500 possibilidades a cada escala. Mas para comer, não sei exatamente o porquê. Como eu disse na pergunta, ele apenas se teletransporta (aka move vários espaços em um turno) e fica lá sem fazer nada. Coloquei um alerta pouco antes do retorno e parece estar sempre dando as instruções certas.
Azul
Talvez isto: "Sua IA deve levar menos de um segundo para fazer uma jogada, caso contrário, o PASS será assumido como sua escolha.". Não li o controlador, mas se estiver demorando mais de um segundo, está assumindo PASS?
precisa saber é o seguinte
@ Mwr247 Vou dar uma olhada nisso, mas parece improvável, pois estava levando <1 segundo (ou pelo menos eu pensei) na minha máquina. Ainda assim, nunca é demais olhar. Obrigado!
Azul
@ Mwr247 Depois de mais alguns testes, não é isso. Está tomando decisões quase tão rápido (pelo menos para mim) quanto o NaiveAi. Além disso, você são mais propensos a experiência de teletransporte em grandes mapas
Azul
1

NaiveAI

Começando com r=0, observe todos os tokens com distância do táxi rda sua posição. Se houver, escolha uma que daria a maior pontuação se você a obtivesse agora. Caso contrário, aumente rem 1 e tente novamente.

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";
    }
  }
}
Melão Fricativo
fonte
1

KindaRandomAI

A cada turno, faça o seguinte: Se houver um token em sua posição, "COMA". Caso contrário, mova-se em uma direção viável aleatória, ou seja, se você estiver na borda esquerda, não diga "ESQUERDA".

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;
    }
}
Melão Fricativo
fonte
-1 não completamente aleatório
CalculatorFeline
Isso é melhor!.
CalculatorFeline
1

LazyBot

Só come alguma coisa se ele aparecer nela. Isso não tem chance de ganhar, mas o desafio não tinha um desses, então por que não.

lazyBot = function (player1) {
    this.yourMove = function(b) {
        return "EAT";
    }
}
Bálint
fonte
11
Cada koth tem uma EmoWolf ...
Azul
3
@ Blue Não é 100% emo, ele tenta comer.
Bálint
1

MirrorBot

Deve ser chamado de "forragem de canhão"

Descrição: Move exatamente o oposto do que o outro jogador fez

Justificativa: eu queria ter uma programação confortável em JS novamente. Isso não deve ganhar

Vai bater: Ninguém

Perderá para: Todos

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;
    }
}
Azul
fonte
Existem alguns problemas com o seu código. Direita e Esquerda não são opostas, e sua definição de função para yourMove não é uma sintaxe válida. Meu código também estava quebrado antes, portanto, no processo de encontrar e corrigir o problema no meu código, eu também corrigi seu código. Você pode olhar para o código fixo no meu script.
Fricative Melon
@FricativeMelon Corrigi a definição de função quebrada. Eu tenho que contestar a afirmação de que o direito não é oposto.
Azul
0,0 é o canto superior esquerdo, então x positivo é direito e x negativo é deixado. se o novo x-pos tem um valor maior que o antigo x-pos, o outro jogador se moveu para a direita, então você deve se mover para a esquerda e vice-versa. Além disso, você deve usar em var out = "EAT";vez de out = "EAT";, pois o último define uma variável global. Se clicar um pouco, a terceira e a quarta linhas não fazem nada e também podem ser removidas e oppodem ser uma variável local, como em outvez de uma propriedade.
Fricative Melon
@FricativeMelon ah, entendo o que você está dizendo. Eu atualizei o código. Obrigado!
Azul
Coloquei seu novo código no script e ele está funcionando agora. Não bate RandomAI embora :(
Fricative Melon
0

OneTarget

Encontra o token que fornecerá mais pontos no menor tempo e seguirá para esse. Classifica as fichas da mesma cor um pouco mais por causa do efeito cumulativo.

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
fonte
0

Quantidade

Tudo o que o QuantityPlayer se importa é com a quantidade de pontos que ele come, não com o valor ou a cor dos pontos. Ele sabe que, embora todos os pontos sejam diferentes, eles devem ser tratados da mesma forma.

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
fonte