KOTH : 모두가 토큰을 좋아합니다


24

이 게임에서 두 명의 플레이어는 가장 많은 점수의 토큰을 먹기 위해 경쟁하지만 비틀기가 있습니다! 같은 색깔의 행에 여러 개의 토큰을 먹으면 점점 보너스가 증가하지만 조심하십시오. 그렇지 않으면 상대방이 원하는 토큰을 먹음으로써 계획을 방해합니다!

규칙 :

  • 1 대 1
  • n x n 보드 (5x5에서 15x15 사이의 임의 크기)
  • 당신과 당신의 상대는 같은 무작위 셀에서 생성됩니다
  • 보드 전체에 걸쳐 1-3의 값을 갖는 일부 셀에서 무작위로 생성 된 숫자가됩니다.
  • 2 * (보드 너비) 토큰이 생성되지만 재정의가 발생할 수 있으므로 우연히 줄어 듭니다.
  • 각 숫자는 16 진수 RGB 형식의 빨강, 녹색 또는 파랑의 3 가지 색상 중 하나입니다.
  • 각 라운드에서 플레이어 1이 이동하고 보드가 업데이트 된 다음 플레이어 2가 이동하고 보드가 업데이트됩니다. 따라서 각 플레이어는 보드 상태의 변화에 ​​따라 이전 플레이어의 움직임을 효과적으로 알 수 있습니다. 이것은 후술하는 바와 같이 게임이 끝날 때까지 계속된다.
  • 한 차례에 6 가지 가능한 행동이 있습니다 : UP, RIGHT, DOWN, LEFT, EAT, PASS
  • 4 가지 이동 명령은 설명이 필요하며 자신의 차례를 통과 할 수 있습니다. 당신이 무의미한 움직임을 돌려 주면, 우리는 당신이 합격을 의미한다고 가정 할 것입니다. 보드 가장자리에서 벗어나려고하면 움직이지 않습니다. 가장자리가 줄 바꿈되지 않습니다.
  • EAT는 현재 같은 공간에있는 숫자를 사용합니다.
  • 당신은 당신이 소비하는 숫자만큼 많은 포인트를 얻습니다
  • 같은 색의 행에서 2 개의 숫자를 먹으면 +1을 얻습니다.
  • 같은 색깔의 행에서 3 개의 숫자를 먹으면 +2
  • 같은 색의 연속으로 m 개의 숫자를 먹으면 + (m-1)
  • 이 보너스는 누적으로 더해 지므로 m을 연속으로 구하면 다른 색을 먹을 때까지 총 보너스에서 m * (m-1) / 2가됩니다.
  • 게임 종료 조건 :
    • 모든 숫자가 소비됩니다
    • 4 * (보드의 너비) 턴은 어느 플레이어에 의해 발생하는 효과적인 식사 (토큰이없는 "EAT"라고 말함)없이 사라졌습니다 (모든 토큰은 2 * (폭) 이동하므로 두 플레이어 모두 단일 대상 토큰을 염두에 두지 않으면이 범위를 능가합니다.)
  • AI가 움직이려면 1 초도 걸리지 않습니다. 그렇지 않으면 PASS가 선택됩니다.

토너먼트는 100 또는 1000과 같이 많은 라운드를 가진 라운드 로빈이 될 것입니다. 무작위 보드가 생성되고, 주문 된 각기 다른 플레이어 쌍이 해당 보드에서 진행됩니다. 토너먼트가 끝나면 우리는 총 점수로 사람들의 순위를 매길 것입니다. 따라서 당신이 게임을 위해 플레이어 2 인 경우에도, 당신의 목표는 가능한 많은 점수를 얻는 것입니다.

AI 제출 : 컨트롤러가 지원하는 언어는 Javascript입니다. 여러 제출이 허용됩니다. 모두 다음과 같은 객체의 생성자를 제출합니다.

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

입력 player1은 플레이어 1인지 아닌지를 나타내는 부울입니다. 생성자는 yourMove함수 를 가져야 하지만 추가 함수 나 값을 여러 개 가질 수 있습니다. 전역 변수를 정의하지 말고 객체에 변수로 넣으십시오. 매 경기가 시작될 때마다 새로운 버전의 물체가 생성되며, yourMove현재 보드를 차례대로 입력 할 때마다 차례대로 호출되며 유효한 이동을 반환해야합니다.

b에 대한 입력 은 현재 보드 yourMove복사본 이며, 여기에는 입력 예제가있는 생성자가 있지만 직접 호출 할 수는 없습니다.

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] [b]는 왼쪽 상단부터 시작하여 x = a, y = b의 토큰입니다.

컨트롤러 : 다음 은 GitHub의 컨트롤러에 대한 링크입니다. 게임과 라운드 로빈의 작동 방식을 확인하기 위해 실행할 수있는 html 파일이며, 두 개의 AI, 매 턴마다 임의의 방향으로 이동하지만 그 위치에서 토큰을 먹는 임의의 AI와 함께 제공됩니다. 가장 많은 점수를주는 가장 가까운 토큰을 찾습니다. 제출할 때마다 각 AI를 추가하겠습니다.

아래는 기본 AI에서 컨트롤러를 실행할 수있는 스 니펫입니다. 현재 AI :

  • 킨덤 랜덤 AI
  • 나이브 AI
  • 미러 봇
  • 배고픈 봇


12
예, KOTH! 그것은 마지막 것부터 영원히되었습니다.
TheNumberOne

2
동의, 나는 좋은 KOTH를 사랑하고 이것은 위대한 전제로 보인다. 나는 js에 약간 녹색이다. 플레이어 객체 내에 결과를 저장할 수 없다면 어떻게 움직일 때 게임 상태를 유지합니까?
DoctorHeckle

보드 너비가 함수의 어느 곳에 나 전달됩니까?
TheNumberOne

@BentNeeHumor 예, player1부울에 사용되는 yourMove함수 는 AI의 생성자이며 현재 보드를 입력으로 사용 하는 함수 가 있습니다 b.
마찰적 멜론

1
@DylanSp 때로는 공모 가능성으로 인해 허용되지 않지만이 경우에는 공모가 최소한의 이점을 갖기 때문에 여러 번 제출할 수 있습니다.
마찰의 멜론

답변:


4

배고픈 봇

포인트 시스템을 사용하여 각 토큰을 추구하는 가치에 가중치를 추가하십시오. 고려할 때 다양한 요소를 사용하고 매번 재평가하여 최상의 전략을 따르도록합니다.

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

당신은 파이썬 프로그래머입니까?
CalculatorFeline

@CatsAreFluffy 정말 ...?
Mwr247

방금 당신이 생각했다 self:)
CalculatorFeline

왜 사용 self합니까? this충분 하지 않습니까?
Conor O'Brien

2

경로 로봇

약어는 Pathfinding And Tree Heuristics Bot의 약자

편집 : 현재 AI의 순위는 다음과 같습니다.

  1. 배고픈 봇 (6422)
  2. PATH 봇 (4591)
  3. 나이브 AI (3811)
  4. 킨덤 랜덤 AI (618)
  5. 미러 봇 (193)
  6. 레이지 봇 (25)

github의 완전한 컨트롤러 연결

설명 : NaiveAI와 마찬가지로이 봇은 가장 많은 점수를주는 가장 가까운 토큰을 찾습니다. 그러나 각 움직임의 결과를 최대 6 번 시뮬레이션합니다.

이론적 근거 : NaiveAI는 이미 꽤 좋기 때문에 더 좋을 것입니다. 코드를 먼저 보지 않고 (큰 실수).

박자 : HungryBot
를 제외한 모두 루스

문제 :

  • 증가 된 줄무늬를 시뮬레이션 할 수 없습니다
  • 최상의 토큰을 계산하는 동안 정지
  • 순간 이동 가능

나는 왜 그것이 왜 순간 이동을했는지 모르지만 그것을 고쳤다. 오래된 비디오 : https://youtu.be/BIhSKycF9iA

전체 코드 :

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

SLaNTbot이 회전 속도를 늦추고 CPU의 15 %를 먹습니다 ... D : 편집 : 그리고 아무것도 먹지 않습니까?
Mwr247

@ Mwr247 속도, 예, 그것은 모든 틱마다 ~ 2500 가능성을 모델링합니다. 그러나 먹는 것에 대해서는 왜 그런지 정확히 모르겠습니다. 내가 질문에서 말했듯이, 그것은 단지 순간 이동 (일명 여러 공간을 1 턴으로 이동)하고 아무것도하지 않고 거기에 앉아 있습니다. 나는 귀환 직전에 경고를했으며 매번 올바른 지시를 내리는 것 같습니다.
Blue

어쩌면 이것은 : "당신의 AI가 움직이려면 1 초도 걸리지 않을 것입니다. 그렇지 않으면 PASS가 당신의 선택으로 간주 될 것입니다." 컨트롤러를 읽지 못했지만 1 초 이상 걸리면 PASS를 가정합니까?
Mwr247

@ Mwr247 나는 그것에 대해 살펴볼 것이지만 내 컴퓨터에서 <1 초 (또는 그래도 나는) 시간이 걸리는 것 같지는 않습니다. 그럼에도 불구하고 결코 아프지 않습니다. 고맙습니다!
Blue

@ Mwr247 좀 더 테스트 한 후에는 그렇지 않습니다. 그것은 NaiveAi만큼 (최소한 나에게) 거의 빠른 결정을 내립니다. 또한 큰지도에서 순간 이동을 경험할 가능성이 더 높습니다
Blue

1

나이브 AI

로 시작하여 r=0택시 택시 거리가 현재 r위치에서 떨어진 모든 토큰 을 확인하십시오. 있다면, 지금 당장 얻은 경우 가장 높은 점수를 줄 수있는 것을 선택하십시오. 그렇지 않으면 r1 씩 늘리고 다시 시도하십시오.

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

1

킨덤 랜덤 AI

매 턴마다 다음을 수행하십시오. 귀하의 위치에 "EAT"토큰이있는 경우. 그렇지 않으면 임의의 실행 가능한 방향으로 이동하십시오. 예를 들어 왼쪽 가장자리에있는 경우 "LEFT"라고 말하지 마십시오.

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

-1 완전히 무작위가 아님
CalculatorFeline

그게 낫다!.
CalculatorFeline


1

미러 봇

"캐논 사료"라고합니다

설명 : 다른 플레이어와 정확히 반대 방향으로 움직입니다.

이론적 근거 : JS에서 편안한 프로그래밍을 다시하고 싶었다. 이기는 안된다

이길 것입니다 : 아무도

잃을 것이다 : 모두

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

코드에 몇 가지 문제가 있습니다. 오른쪽과 왼쪽이 반대가 아니고 yourMove에 대한 함수 정의가 유효한 구문이 아닙니다. 내 코드도 이전에 손상되었으므로 내 코드에서 문제를 찾아 수정하는 과정에서 코드도 수정되었습니다. 내 스크립트에서 고정 코드를 볼 수 있습니다.
마찰의 멜론

@FricativeMelon 깨진 함수 정의를 수정했습니다. 권리가 반대가 아니라는 주장에 반대해야합니다.
Blue

0,0은 왼쪽 위 모서리이므로 양의 x는 오른쪽이고 음의 x는 왼쪽입니다. 새 x-pos가 이전 x-pos보다 가치가 높으면 다른 플레이어가 오른쪽으로 이동 했으므로 왼쪽으로 이동해야합니다. 또한 나중에 전역 변수를 정의하므로 var out = "EAT";대신 대신 사용해야 out = "EAT";합니다. 조금만 살펴보면 세 번째와 네 번째 줄은 아무것도하지 않으며 제거 op할 수 있으며 out속성 대신 로컬 변수가 될 수 있습니다 .
마찰의 멜론

@ FricativeMelon 아, 나는 당신이 말하는 것을 얻습니다. 코드를 업데이트했습니다. 고맙습니다!
Blue

새 코드를 스크립트에 넣었으며 현재 작동 중입니다. 하지만 :( RandomAI를 이길하지 않습니다
마찰음 멜론

0

OneTarget

가장 적은 시간에 가장 많은 점수를주고 그에 대한 토큰을 찾습니다. 누적 효과로 인해 동일한 색상 토큰의 순위가 약간 높아집니다.

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

0

QuantityPlayer

QuantityPlayer가 걱정하는 모든 것은 점의 가치 나 색이 아니라 먹는 점의 양입니다. 그는 모든 점이 다르더라도 동일하게 취급해야한다는 것을 알고 있습니다.

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

}

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.