공식 기능-힐 콘테스트의 개미 여왕


104

라이브보기 | 활발한 답변 | 새로운 답변 추가 | 대화방 | 소스 코드 | 리더 보드

필요할 때마다 새로운 토너먼트. 새로운 플레이어와 새로운 업데이트는 매우 환영합니다.

색깔의 타일을 변경 댄스 플로어에서 여왕 개미

실제 게임 장면이 아닙니다.

각 플레이어는 음식을 수집하는 여왕 인 개미로 시작합니다. 각 음식은 노동자를 생산하기 위해 유지되거나 사용될 수 있습니다. 노동자들은 또한 여왕에게 가져갈 음식을 모 읍니다.

16 명의 플레이어는 한 경기장에서 경쟁합니다. 우승자는 그녀가 30,000 번을 돌린 후 가장 많은 음식을 들고있는 여왕입니다. 잡는 것은 개미가 경기장 광장의 색상을 변경해야만 통신 할 수 있으며 경쟁사 개미에 의해 변경 될 수도 있습니다 ...

게임을보고

이것은 JavaScript 경쟁입니다. 즉, 아래 링크를 클릭하여 브라우저에서 게임을 실시간으로 볼 수 있습니다.

게임을 실시간으로 시청하려면 여기를 클릭하십시오

많은 감사 Helka Homba 원래 스택 코드 조각 언덕 대회의 왕을위한 빨강 파랑 대 - 픽셀 팀 Battlebots블록 건물 봇 떼 웹 브라우저의 아이디어를 제공, KOTH를 주최하고 무겁게 이것에 대한 코드를 알렸다.

샌드 박스와 채팅에 참여한 멋진 사람들의 모든 피드백과 테스트에 감사드립니다.

리더 보드

리더 보드의 최고 장소 사진

(이미지를 클릭하면 전체 순위표 및 공동 장소 설명을 볼 수 있습니다. 공간을 절약하기 위해 소수의 플레이어 만 여기에 표시됩니다.)

그들은 일요일 2에 있었다으로이 리더는 선수를 기반으로 ND 2018년 9월.

스크린 샷

경기장이 게임이 끝날 때 어떻게 보이는지에 대한 이미지. 이미지를 클릭하면 전체 크기로 볼 수 있습니다.

경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지 경기장의 이미지

경기장에서 무슨 일이 일어나고 있으며 이러한 모든 패턴이 어떻게 형성되는지에 대한 아이디어를 얻으려면 게임을 실행하고 경기장 위로 마우스를 가져 가면 확대되고 직장에서 개미를 볼 수 있습니다. 답변에서 매혹적인 설명을 참조하십시오.

경기장

경기장은 사각형 셀의 토 로이드 형 (가장자리) 격자입니다. 너비는 2500이고 높이는 1000입니다. 모든 셀은 색상 1로 시작합니다.

처음에는 정확히 0.1 %의 세포에 음식이 포함됩니다. 2500 조각의 음식은 무작위로 흩어져 있습니다. 게임 중에는 새로운 음식이 소개되지 않습니다.

여왕은 빈 셀에 무작위로 배치되며 서로 인접하지 않을 것이라는 보장은 없습니다 (매우 가능성은 낮음).

개미 능력

  • 시력 : 각 개미는 3 x 3 이웃에있는 9 개의 세포를 봅니다. 이 지역 밖의 다른 개미에 대한 지식이 없습니다. 그것은 9 개의 세포 각각 (다른 개미와 음식)의 내용과 각 세포의 색을 본다 .
  • 기억이 없음 : 각 개미는 보이는 것에 기초하여 결정을 내립니다. 이전 차례에서 한 일을 기억하지 않으며 경기장 세포의 색 이외의 상태를 저장할 방법이 없습니다.
  • 오리엔테이션 없음 : 개미는 그것이 어디에 있는지 또는 어느 방향을 향하고 있는지 알지 못합니다. 북쪽 개념이 없습니다. 3 x 3 이웃은 각 회전을 변경하는 무작위 회전 방향으로 표시되어 안내 할 색상이 없으면 직선으로 걸을 수 없습니다. (매 턴마다 같은 움직임을하면 직선이 아닌 무작위로 움직입니다.)
  • 작업자 이동, 색상 표시 및 생산 : 아래 출력을 참조하십시오 .
  • 불멸 : 이들은 죽을 수없는 고원 개미입니다. 당신은 주위의 색상을 변경하여 경쟁 개미를 혼동하거나 자신의 8 개미로 둘러싼 움직임을 제한 할 수 있지만, 이것과 별개로 해를 입을 수는 없습니다.
  • 음식 운반 : 근로자는 최대 1 개의 음식을 운반 할 수 있습니다. 여왕은 임의의 양의 음식을 운반 할 수 있습니다.
  • 음식의 양도 : 근로자가 여왕과 인접 해있는 경우 (8 가지 방향 중 하나) 다음 방법 중 하나로 음식이 자동적으로 양도됩니다.
    • 자신의 여왕에 인접한 짐꾼이 음식을 여왕에게 옮길 것입니다.
    • 적의 여왕에 인접한 무적의 일꾼은 존재한다면 1 조각의 음식을 훔칩니다.

노동자는 노동자에게서 훔칠 수 없으며, 여왕은 여왕에게서 훔칠 수 없습니다. 또한 노동자는 자신의 여왕에게서 음식을 먹을 수 없으며, 여왕은 적의 노동자에게서 도둑질을 할 수 없습니다.

개미는 차례대로 교대로 돌아가고 개미의 개별 차례가 끝날 때 음식 전이가 발생하며 한 차례를 차지하지 않습니다. 노동자가 여왕 옆으로 움직이는 지 여왕이 노동자 옆으로 움직이는 지에 관계없이 발생하며, 관련된 두 개미가 여전히 움직이기를 원한다면 여전히 발생합니다.

코딩

함수 본문 제공

각 개미는 개미 기능에 의해 제어됩니다. 각 턴마다 플레이어의 개미 기능은 각 개미에 대해 개별적으로 호출됩니다 (플레이어 당 한 번이 아니라 퀸에 대해 한 번, 플레이어가 제어하는 ​​각 작업자에 대해 한 번). 매 턴마다 개미 기능은 입력을 받고 해당 개미에 대한 이동을 반환합니다.

JavaScript 함수의 본문을 보여주는 코드 블록이 포함 된 답변을 게시하면 컨트롤러에 자동으로 포함됩니다 (컨트롤러 페이지를 새로 고침). 플레이어의 이름은 답변의 제목을 양식 # PlayerName(컨트롤러 테이블에서 최대 40 자로 잘립니다)으로 구성합니다.

상태 없음, 시간 없음, 무작위 없음

함수는 전역 변수에 액세스해서는 안되며 회전간에 상태를 저장해서는 안됩니다. 상태 저장과 관련이없는 내장 함수를 사용할 수 있습니다. 예를 들어, 사용은 Math.abs()좋지만 사용 Date.getTime()해서는 안됩니다.

개미 함수는 상태를 저장하지 않고 자체적으로 제공하는 의사 난수 생성기 만 사용할 수 있습니다. 예를 들어, 매 차례 씨앗으로 보이는 색상 / 음식 / 개미를 사용할 수 있습니다. Math.random()거의 모든 의사 난수 생성기와 마찬가지로 다음 숫자로 순서대로 진행하기 위해 상태를 저장합니다.

입력의 임의 방향으로 인해 간단한 임의 전략이 여전히 가능합니다. 항상 같은 방향을 선택하는 개미는 직선 경로가 아닌 임의의 보행을 수행합니다. 이 임의성사용하고이 임의성피하는 간단한 방법은 예제 답변을 참조하십시오 .

개미 기능은 몸 안에 추가 기능을 포함 할 수 있습니다. 이것이 유용한 방법에 대한 예 는 기존 답변 을 참조하십시오 .

Console.log

새로운 도전자 플레이어를 테스트하는 동안 콘솔에 로그인 할 수 있지만 여기에 답변으로 게시 된 플레이어는에 액세스 할 수 없습니다 console.log. 사용하려고하면 편집 할 때까지 오류와 실격이 발생합니다. 이는 리더 보드 토너먼트를 빠르게 유지하는 동시에 새로운 도전자 텍스트 영역에 붙여 넣은 디버깅 코드를 허용하는 데 도움이됩니다.

입력과 출력

입력

입력 방향은 개미와 턴마다 무작위로 선택됩니다. 입력은 0, 90, 180 또는 270도 회전하지만 반영되지는 않습니다.

셀은 영어 읽기 순서로 번호가 매겨집니다.

0 1 2
3 4 5
6 7 8

ant 함수는 view9 개의 보이는 셀 각각에 대한 객체를 포함하는 이라는 배열을받습니다 . 각 객체에는 다음이 있습니다.

color: a number from 1 to 8
food: 0 or 1
ant: null if there is no ant on that cell, or otherwise an ant object

셀에 개미가 포함 된 경우 개미 개체에는 다음이 포함됩니다.

food: 0 or more (maximum 1 for a worker)
type: 1 to 4 for a worker, or 5 for a queen
friend: true or false

개미는 중앙 셀의 개미를 보면 자신의 세부 사항을 확인할 수 있습니다 view[4].ant. 예를 들어, view[4].ant.type여왕의 경우 5, 근로자의 경우 유형을 나타내는 1에서 4 사이의 숫자입니다.

산출

출력은 수행 할 조치를 나타내는 오브젝트로 리턴됩니다. 이것은 다음 중 하나를 가질 수 있습니다.

cell: a number from 0 to 8 (mandatory)
color: a number from 1 to 8 (optional)
type: a number from 1 to 4 (optional)

경우 colortype생략 제로, 다음 cell으로 이동하는 셀을 나타낸다.

color0이 아닌 경우 표시된 셀이 해당 색상으로 설정됩니다.

type0이 아닌 경우 해당 유형의 작업자 개미가 표시된 셀에 작성됩니다. 여왕은 새 노동자를 만들 수 있고, 음식이있는 경우에만 노동자당 한 조각의 음식이 들기 때문에 가능합니다.

출력 예 :

{cell:0}: move to cell 0
{cell:4}: move to cell 4 (that is, do nothing, as 4 is the central cell)
{cell:4, color:8}: set own cell to color 8
{cell:6, type:1}: create a type 1 worker on cell 6
{cell:6, color:1}: set cell 6 to color 1
{cell:6, color:0}: equivalent to just `{cell:6}` - move rather than set color
{cell:6, type:0}: equivalent to just `{cell:6}` - move rather than create worker
{cell:6, color:0, type:0}: move to cell 6 - color 0 and type 0 are ignored

유효하지 않은 출력 :

{cell:9}: cell must be from 0 to 8
{cell:0, color:9}: color must be from 1 to 8
{cell:0, type:5}: type must be from 1 to 4 (cannot create a new queen)
{cell:4, type:1}: cannot create a worker on a non-empty cell
{cell:0, color:1, type:1}: cannot set color and create worker in the same turn

음식이 담긴 세포 위로 개미가 이동하면 음식 조각이 자동으로 픽업됩니다.

작업자 유형

각 작업자가 유형 , 이것은 컨트롤러에 의미가 없습니다 1에서 4까지의 숫자를, 플레이어들이 원하는대로 함께 할 수입니다. 여왕은 모든 노동자를 1 형으로 생산하고 그들 모두에게 동일한 행동을 주거나 다른 행동을 가진 여러 유형의 노동자를 생산할 수 있습니다.

작업자 유형 번호는 작업자가 생성 될 때 사용자가 할당하므로 나중에 변경할 수 없습니다. 당신이 적합하다고 생각하지만 그것을 사용하십시오.

순서 전환

개미는 정해진 순서대로 회전합니다. 게임이 시작될 때 퀸은 무작위 순서로 할당되며 나머지 순서는 바뀌지 않습니다. 여왕이 노동자를 만들면, 그 노동자는 여왕 앞의 위치에서 턴 순서에 삽입됩니다. 이것은 새로운 선수가 첫 턴을하기 전에 모든 선수에 속한 다른 모든 개미가 정확히 한 번만 움직인다는 것을 의미합니다.

플레이어 수 제한

분명히 무제한의 플레이어가 경기장에 들어갈 수 없습니다. 현재 16 개가 넘는 답변이 있으므로 각 게임에는 무작위로 선택된 16 개가 있습니다. 많은 게임의 평균 성능은 단일 게임에서 16 명 이상을 차지하지 않고 모든 플레이어를 지원하는 리더 보드를 제공합니다.

턴당 시간 제한

개미 함수가 호출 될 때마다 15 밀리 초 내에 반환되어야합니다. 개미 기능 제어 외부의 변동으로 인해 시간 제한이 초과 될 수 있으므로 평균이 계산됩니다. 어느 시점에서 평균이 15 밀리 초를 초과하고 지금까지 모든 통화에서 특정 개미 기능에 소요 된 총 시간이 10 초를 초과하면 관련 플레이어가 실격 처리됩니다.

자격 박탈

즉, 플레이어는 이길 수 없으며 개미 기능은 해당 게임 중에 다시 호출되지 않습니다. 그들은 더 이상 게임에 포함되지 않습니다. 리더 보드 게임 도중 토너먼트 머신에서 실격 처리 된 플레이어는 편집 할 때까지 이후의 모든 리더 보드 게임에서 제외됩니다.

플레이어는 개미 (여왕 또는 일꾼)에 대해 다음 중 하나의 자격을 상실합니다.

  • 설명 된 시간 제한을 초과했습니다 (10 초 이상 평균).
  • 출력에 설명 된대로 유효하지 않은 이동을 반환합니다.
  • 이동할 셀에는 개미가 들어 있습니다.
  • 음식과 개미가 들어있는 세포는 이미 짐꾼입니다.
  • 작업자를 생산하는 세포는 비어 있지 않습니다 (음식 또는 개미 포함).
  • 근로자가 근로자를 생산하려고합니다.

단순히 이것을 움직임이없는 것으로 해석하는 것보다 무효 한 움직임에 대한 자격을 박탈하는 것은 가혹한 것처럼 보일 수 있습니다. 그러나 올바른 구현을 시행하면 시간이 지남에 따라 더 흥미로운 전략이 생길 것이라고 생각합니다. 이것은 추가적인 도전이 아니며, 플레이어가 자격을 상실 할 때 코드를 수정하는 데 도움이되는 특정 입력 및 출력과 함께 명확한 이유가 표시됩니다.

여러 답변과 편집

다른 사람들과 팀을 이루지 않으면 여러 답변을 제공 할 수 있습니다. 각 답변이 자신의 승리를 위해서만 노력하고 있다면, 혼동하거나 조작하기 위해 셀의 색상을 변경하는 것을 포함하여 특정 다른 전략의 약점을 활용하도록 전략을 조정할 수 있습니다. 더 많은 답변이 나오면 주어진 게임에서 특정 플레이어를 만날 가능성이 줄어 듭니다.

원할 때마다 답변을 편집 할 수도 있습니다. 새로운 답변을 게시하거나 기존 답변을 편집하는 것은 귀하에게 달려 있습니다. 게임이 거의 동일하게 많은 변형으로 넘쳐나 지 않는다면 아무런 문제가 없을 것입니다.

다른 사람의 답변을 변경 한 경우 답변을 다른 사람의 답변과 연결하여 크레딧을 제공해야합니다.

채점

각 게임이 끝날 때, 플레이어의 점수는 여왕이 가지고있는 음식이 적은 다른 플레이어의 수입니다. 근로자가 운반하는 음식은 포함되지 않습니다. 이 점수는 순위표에 추가되며 게임당 평균 점수 순으로 표시됩니다.

공동 장소는 지금까지 플레이 한 게임의 6 개 하위 집합간에 플레이어 순서가 아직 일치하지 않음을 나타냅니다. 게임 목록은 6 개의 하위 세트로 나뉩니다. 이는 주어진 플레이어 쌍에 잘못된 순서로 고유 한 장소가 할당 될 확률이 5 % 미만일 최소값이기 때문입니다.

잡담

여기에 의견 섹션을 명확하게 유지하려면 질문과 토론을 위해 전용 대화방을 사용하십시오 . 이 게시물에 대한 댓글은 잠시 후에 지워질 수 있지만 대화방의 메시지는 영구적으로 유지됩니다.

알려 드리기 위해 코드 작동 방식에 대한 명확하고 흥미로운 설명이 포함 된 답변을 찬성하는 경향이 있습니다.


2
@DestructibleLemon이 의견을 읽고있는 누군가를 위해, 나는 대화방에서 답했습니다
trichoplax


7
이봐, 나는 물건을 만들었다 ! 이 도전에서 영감을 얻었고 Formic Functions 테스트 구현이 포함되어 있기 때문에 흥미로울 입니다.
Dave

2
@Dave 컨트롤러가 엄청나게 빠릅니다 :)-게임이 끝날 때 여왕이 음식에 묶여있는 경우 점수가 원래 점수와 다른 것 같습니다. 점수는 여왕이 음식을 보유한 다른 참가자의 수 여야합니다 . 예를 들어, 만약 3 명의 플레이어가 마지막에 0 개의 음식을 가지고 있다면, 3 명이 아닌이 게임에서 모두 0 점을 얻습니다.
GNiklasch

2
@GNiklasch 감사합니다; 결정된. 또한 나는 당신의 개미가 게임을 지배한다는 것을 알았습니다. 감동적인!
Dave

답변:


20

법의학 개미

모든 대답은 동일한 하위 수준 도우미 기능 집합을 공유합니다. 이 답변과 관련된 코드를 보려면 "고수준 논리가 여기서 시작됩니다"를 검색하십시오.

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var PARTNER = 1;
var SENTINEL = 2;

var COL_DANCING1 = 8;
var COL_DANCING2 = 7;
var SAFE_COLOURS = random_colour_band(colours_excluding([WHITE, COL_DANCING1]));

function pass_time() {
  // Wait patiently for the blockage to go away by setting
  // random cell colours (unless we're near the sentinel)
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && friend_at(i) === SENTINEL) {
      return null;
    }
  }
  return {cell: 0, color: SAFE_COLOURS.next()};
}

function move_sentinel(me, buddies) {
  // Our job is to be a sentinel showing when the queen has wrapped around.
  // We are created first, so will move first.
  // We won't find any food.

  if(!buddies[QUEEN] && !buddies[PARTNER]) {
    // No ongoing dance; make sure our state is good for when they arrive
    return try_all_angles([
      {cell: CENTRE, color: WHITE},
      (rot) => ({cell: rot[1], color: COL_DANCING2}),
      (rot) => ((view[rot[0]].color === COL_DANCING1)
        ? {cell: rot[0], color: SAFE_COLOURS.next()}
        : null)
    ]);
  }

  // Dance when queen passes
  var danceStage = view[CENTRE].color;

  if(danceStage === WHITE) {
    // Dance has not begun yet, but queen & partner are nearby
    return try_all_angles((rot) => {
      if(friend_at(rot[5]) === QUEEN && friend_at(rot[8]) === PARTNER) {
        return {cell: CENTRE, color: COL_DANCING1};
      }
    });
  }

  if(danceStage === COL_DANCING1) {
    if(buddies[PARTNER]) {
      return null; // Wait for partner to see us
    }
    // Partner saw us @8 and moved down, queen followed.
    // We must also move down (will end up on a COL_DANCING2)
    return try_all_angles((rot) =>
      ((friend_at(rot[8]) === QUEEN) ? {cell: rot[7]} : null));
  }

  // Move towards queen counter-clockwise when she's diagonally connected
  return try_all_angles((rot) =>
    ((friend_at(rot[2]) === QUEEN) ? {cell: rot[1]} : null));
}

function move_partner(me, buddies) {
  // Our job is to travel with the queen and keep her oriented.
  // We are created second, so move after the sentinel.
  // Any food we find will immediately go to the queen, since
  // we are adjacent at all times.

  // Queen will be N of us; orient ourselves
  var rot = identify_rotation((rot) => friend_at(rot[1]) === QUEEN);

  if(!rot) {
    // Queen is lagging or lost;
    return null;
  }

  var danceStage = view[rot[0]].color;
  if(
    friend_at(rot[0]) === SENTINEL &&
    (danceStage === COL_DANCING1 || danceStage === COL_DANCING2)
  ) {
    // Dance down (queen will follow)
    return {cell: rot[7]};
  }

  if(view[rot[0]].ant) {
    // Queen is blocked
    return null;
  }

  // Lead queen if both can move
  return {cell: rot[3]};
}

function move_queen(me, buddies) {
  // Our job is to travel over the entire level collecting food.
  // We move last.

  if(buddies[PARTNER]) {
    // Partner will be S or SW of us; follow if they are ahead
    return try_all_angles((rot) =>
      (friend_at(rot[6]) === PARTNER) ? {cell: rot[3]} : null);
  }

  var rot = identify_rotation((rot) => friend_at(rot[3]) === SENTINEL);
  if(rot && view[rot[0]].color >= 7) {
    // Dance down (follow partner)
    return {cell: rot[7]};
  }

  // We're on our own, or the buddy strategy failed. Start again.

  rot = identify_rotation((rot) => friend_at(rot[5]) === SENTINEL);
  if(rot && me.food >= 1) {
    // Already have a sentinel; just need a partner
    return best_of([
      {cell: rot[7], type: PARTNER},
      {cell: rot[6], type: PARTNER},
    ]);
  } else if(me.food >= 2) {
    // Create sentinel first so that we'll know to create the partner next.
    // (ensure the sentinel is created on a white cell so that it won't
    // think it's dancing)
    return try_all_angles(
      (rot) => ((view[rot[5]].color === WHITE)
        ? {cell: rot[5], type: SENTINEL} : null),
      (rot) => ({cell: rot[5], color: WHITE})
    );
  }

  // Not able to start yet; fall back to lone behaviour:
  // Random-walk until we find or make a buddy
  return best_of([
    grab_nearby_food,
    fast_diagonal.bind(null, SAFE_COLOURS),
    go_anywhere
  ]);
}

return play_safe([move_agent([
  PARTNER, move_partner,
  SENTINEL, move_sentinel,
  QUEEN, move_queen,
]), pass_time]);

법의학 개미는 그리드를 청소하는 과학적인 접근 방식을 취합니다. 음식에 대한 초기 열광적 인 출격 후 2 명의 일개미가 만들어집니다. 역할은 다음과 같습니다.

여왕은 파트너와 팀을 이루어 빛의 속도로 직선으로 여행합니다. 그들 중 어느 것도 음식을 가져 오기 위해 갈라지지 않을 것입니다. 그들은 넘어 질 때마다 잡아 먹습니다.

파트너

파트너는 여왕과 같은 방향을 향하게하여 여왕과 함께 움직입니다. 두 개미는 한 턴마다 1 칸씩 움직일 수 있기 때문에 땅을 그리는 데 시간을 낭비하지 않고 직선을 유지할 수 있습니다.

파트너가 음식을 발견하면 항상 인접 해 있기 때문에 즉시 여왕에게 갈 것입니다.

보초

가장 중요한 개미. 이것은 여왕과 파트너가 그것을 도달 할 때까지 그대로 둔 다음 2 픽셀을 따라 움직이라고하고 2 픽셀 자체를 움직입니다. 이로 인해 여왕과 파트너는 전체 보드를 점진적으로 쓸어냅니다 (어쨌든 약 30 픽셀). 여왕이 근처에있을 때만 움직이므로, 찾은 음식은 즉시 넘겨집니다.

여가 시간에 센티넬의 취미에는 주변의 땅을 무작위로 칠해 경쟁자를 망치게하는 것이 포함됩니다.


이들은 매우 일관되게 수행됩니다. 그들 사이에서 그들은 각 프레임마다 2 개의 셀을 쓸 수 있는데, 30000 개가 넘는 프레임은 60000 개의 셀을 의미하고, 0.1 %는 음식을 포함하고 있습니다.


(그리고 여기에 질문이 베타 인 동안 준비한 다른 것이 있습니다! — 지금은 끝났습니다. 이것들은 꽤 빨리
Dave

점수는 현저하게 일치합니다. 경기장이 더 많은 경쟁자로 가득 차면서 어떻게 영향을 받는지 보는 것이 흥미로울 것입니다.
trichoplax

여왕의 반대편에 다른 파트너를 추가하는 것이 도움이 될지 궁금합니다.
K Zhang

1
@ KZhang 나는 그것을 생각합니다 (이론적으로 점수를 ~ 90으로 올릴 것입니다). 그러나 두 사람을 센티넬과 동기화하기가 충분하지 않습니다! "모두를 2 픽셀 위로 이동"댄스는 알아내는 데 시간이 걸렸습니다. 3 픽셀로 가면 내가 의존했던 트릭 중 하나를 차단할 것입니다 (센티넬은 미리 공간을 준비합니다).
Dave

첫 번째 리더 보드의 상단 ...
trichoplax

18

슬라이딩 광부 6.4

const DEBUG = false;
const ADD = (a,b) => a + b;
var toReturn;
var me = view[4].ant;
me.me = true; // for basedOn to know
var food = me.food;
var type = me.type;
var isQueen = type == 5;

// raw directions
const UL = 0; const U  = 1; const UR = 2;
const L  = 3; const C  = 4; const R  = 5;
const DL = 6; const D  = 7; const DR = 8;

// directions from the reference point
const ul = 16; const u  = 17; const ur = 18;
const l  = 19; const c  = 20; const r  = 21;
const dl = 22; const d  = 23; const dr = 24;
const rp = 16;

function allRots (arr) {
  return [arr,
  [arr[2], arr[5], arr[8],
   arr[1], arr[4], arr[7],
   arr[0], arr[3], arr[6]],

  [arr[8], arr[7], arr[6],
   arr[5], arr[4], arr[3],
   arr[2], arr[1], arr[0]],

  [arr[6], arr[3], arr[0],
   arr[7], arr[4], arr[1],
   arr[8], arr[5], arr[2]]];
}
var allVRots = allRots(view);

function rotateCW3([[a,b,c],[d,e,f],[g,h,i]]) {
  return [[g,d,a],[h,e,b],[i,f,c]]
}

function on (where, what) {
  if (Array.isArray(where)) return where.some(c=>on(c, what));
  if (Array.isArray(what)) return what.some(c=>on(where, c));
  return basedOn(get(where), what);
}
function find (what) {
  return view.findIndex(c=>basedOn(c, what));
}
function findAll (what) {
  return view.map((c,i)=>[c,i]).filter(c=>basedOn(c[0], what)).map(c=>c[1]);
}
function count (what) {
  return findAll(what).length;
}
function findRel (what) {
  return ref(find(what));
}
function findAllRel (what) {
  return findAll(what).map(c=>ref(c));
}
function found (what) {
  return find(what) != -1;
}
function get (dir) {
  if (Array.isArray(dir)) return dir.map(c=>get(c));
  return view[raw(dir)];
}
function deq (a, b) {
  return a==b || raw(a)==raw(b);
}

// returns a random number from 0 to 4, based on the rotation. Will always have a possibility of being 0
function random4 () {
  var scores = allRots(view.map(c=>c.color)).map((c) => {
    let cscore = 0;
    c.forEach((c) => {
      cscore*= 8;
      cscore+= c-1;
    });
    return cscore;
  });
  var bestscore = -1, bestindex = 1;
  scores.forEach((score, index) => {
    if (score > bestscore) {
      bestscore = score;
      bestindex = index;
    }
  })
  return bestindex;
}

function rotate (what, times) {
  for (var i = 0; i < times; i++) what = [2,5,8,1,4,7,0,3,6][what];
  return what;
}

function raw(dir) {
  if (dir&rp) return rotate(dir&~rp, selectedRot);
  return dir;
}

function ref(dir) {
  if (dir == -1) return -1;
  if (dir&rp) return dir;
  return rotate(dir, 4-selectedRot)|rp;
}

function move(dir, force) {
  if (Array.isArray(dir)) return dir.some(c=>move(c, force));
  dir = raw(dir);
  return result({cell:dir}, force);
}

function color(dir, col) {
  if (Array.isArray(dir)) return dir.some(cdir => !color(cdir, col));
  dir = raw(dir);
  if (view[dir].color == col) return true;
  result({cell:dir, color:Math.abs(col)});
  return false;
}

function rcolOf(what) {
  return Number.isInteger(what)? what : what.color;
}

function colOf(what) {
  return Math.abs(Number.isInteger(what)? what : what.color);
}
function sees(c1,c2) {
  c1 = raw(c1);
  c2 = raw(c2);
  return Math.abs(c1%3-c2%3)<2 && Math.abs(Math.floor(c1/3)-Math.floor(c2/3))<2;
}

function spawn(dir, t) {
  if (Array.isArray(t)) return t.some(c=>spawn(dir, c));
  if (Array.isArray(dir)) return dir.some(c=>spawn(c, t));
  dir = raw(dir);
  return result({cell:dir, type:t});
}
// repairs a single cell
function correct(dir) {
  dir = raw(dir);
  let col = colOf(selectedPt[dir]);
  if (col && view[dir].color != col) {
    color(dir, col);
    return false;
  }
  return true;
}
// if pattern is repaired, returns true, otherwise fixes one cell
// firstdirs is lowercase (if you do want it to be from the patterns POV)
function repair(firstdirs, onlyThose) {
  //log("FD",firstdirs);
  var found = [];
  view.forEach((v, i) => {
    let col = colOf(selectedPt[i]);
    if (col && v.color != col) {
      found.push(i);
    }
  });
  if (found.length == 0) return true;
  if (firstdirs && (firstdirs = firstdirs.map(c=>raw(c))).some(c=>found.includes(c))) {
    let dir = firstdirs.find(c=>found.includes(c));
    let col = colOf(selectedPt[dir]);
    color(dir, col);
    return false;
  }
  if (!onlyThose) {
    let dir = found[random4() % found.length];
    let col = colOf(selectedPt[dir]);
    color(dir, col);
    return false;
  } else return true;
}

function flatten (arr) {
  return arr.reduce((a,b)=>a.concat(b));
}

var selectedHp, selectedVp, selectedPt, selectedRot;

class Pattern {
  constructor(pattern, inherit) {
    this.pt = pattern;
    if (inherit) {
      this.vp = inherit.vp;
      this.hp = inherit.hp;
      this.rot = inherit.rot;
    } else {
      this.vp = 0;
      this.hp = 0;
      this.rot = 0;
    }
  }

  rotateClockwise() {
    var arr = [];
    for (var i = 0; i < this.pt[0].length; i++) {
      var sarr = [];
      for (var j = this.pt.length-1; j >= 0; j--) {
        sarr.push(this.pt[j][i]);
      }
      arr.push(sarr);
    }
    //log(arr);
    var res = new Pattern(arr, this);
    res.rot = (this.rot+1) % 4;
    return res;
  }

  select(x, y, w, h) {
    var res = new Pattern(this.pt.slice(y, y+h).map(c=>c.slice(x, x+w)), this);
    res.hp+= x;
    res.vp+= y;
    return res;
  }

  rots(dir) {
    var pts = [];
    var pt = new Pattern(this.pt, this);
    for (let i = 0; i < this.lengthIn(dir); i++) {
      pts.push(pt);
      pt = pt.rotate(dir);
    }
    return pts;
  }

  map(fn) {
    return new Pattern(this.pt.map(ln=>ln.map(fn)), this);
  }

  lengthIn(dir) {
    if (dir == U || dir == D) return this.pt.length;
    else if (this.pt.length > 0) return this.pt[0].length;
    else return 0;
  }
  rotate(dir) { // moves the center to that direction, shifting the side
    if (dir == R) {
      var res = new Pattern(this.pt.map(c=>((h,...t)=>t.concat(h))(...c)), this);
      res.hp++;
      return res;
    }
    if (dir == L) {
      var res = new Pattern(this.pt.map(a=>a.slice(-1).concat(a.slice(0,-1))), this);
      res.hp++;
      return res;
    }
    if (dir == D) {
      var res = new Pattern(((h,...t)=>t.concat([h]))(...this.pt), this);
      res.vp++;
      return res;
    }
    throw "rotate unimplemented dir!";
  }

  center(dir) { // moves the center to that direction
    if (dir == R) {
      var res = new Pattern(this.pt.map(c=>((h,...t)=>t.concat(0))(...c)), this);
      res.hp++;
      return res;
    }
    if (dir == L) {
      var res = new Pattern(this.pt.map(a=>[0].concat(a.slice(0,-1))), this);
      res.hp++;
      return res;
    }
    if (dir == D) {
      var res = new Pattern(((h,...t)=>t.concat([new Array(h.length)]))(...this.pt), this);
      res.vp++;
      return res;
    }
    throw "center unimplemented dir!";
  }

  setSize(xs, ys) {
    var arr = [];
    for (let y = 0; y < ys; y++) {
      var ca = [];
      for (let x = 0; x < xs; x++) {
        ca.push(this.pt[y % this.pt.length][x % this.pt[0].length]);
      }
      arr.push(ca);
    }
    return new Pattern(arr, this);
  }

  static add(pattern, action, scorer, presetRot) {
    if (Array.isArray(pattern)) pattern = new Pattern(pattern);
    pattern = pattern.setSize(3,3);
    var cpt = pattern.setSize(3,3);
    var orig = cpt.pt;
    for (let i = 0; i < 4; i++) {
      cpt = cpt.rotateClockwise();
      if (!presetRot || presetRot == cpt.rot) {
        cpt.action = action;
        cpt.scorer = scorer;
        cpt.raw = orig;
        cpt.view = allVRots[cpt.rot];
        allPatterns.push(cpt);
      }
    }
  }


  static choose() {
    var maxScore = -1e307;
    var nextScore = -1e308;
    var maxPt;
    allPatterns.forEach((c) => {
      // null  = easy
      // 0     = bad queen
      // false = no match
      // >0    = score
      var falseN = 0;
      var corrects = c.raw.reduce((a,b)=>a.concat(b)).map((guess, index) => {
        var bo = basedOn(c.view[index], guess, true);
        var ant = guess.ant;
        if (ant && basedOn(c.view[index], {ant})) bo+= 1;
        if (bo === 0) return 0;
        if (bo === false) return false;
        if (bo && rcolOf(guess) > 0) return bo;
        var easy = rcolOf(guess)<=0;
        if (easy) {
          falseN++;
          return null;
        }
        return bo;
      });
      var corrstring = corrects.map((chr,i)=>chr>0? (colOf(c.raw[Math.floor(i/3)][i%3])==1? "W" : "#") : chr===null? "-" : " ").join("");
      function match(pt) {
        return new RegExp(pt.replace(/@/g, "[#-W]").replace(/C/g, "[#-]")).test(corrstring);
      }
      var score = corrects.reduce(ADD)*9/(9-falseN);
      if (match(".?(...)?##.##.*")) {
        if (match("(...)?@@@@@@.*|.?@@.@@.@@.?")) score+= foundEnemy? 5 : 3;
        else score+= foundEnemy? 3 : 1;
      } else if (!foundEnemy) score = Math.min(score/2, 5);
      if (c.scorer instanceof Function) score = c.scorer(score, c, corrects, falseN, match);
      if (DEBUG && score > -1) log(
        "scored", score,
        "corr", /*corrects.map(c =>
          (c===false?"F":c===null?"N":c===true?"T":c)
        )*/corrstring,
        "pt", c.raw.map(c=>c.ant? "A"+c.ant.type : c), c.hp, c.vp);
      if (score >= maxScore) {
        nextScore = maxScore;
        maxScore = score;
        c.corrstr = corrstring;
        maxPt = c;
      }
    });
    var flattened = maxPt.pt.reduce((a,b)=>a.concat(b));
    Pattern.hardcorr = flattened.map((guess, index) => rcolOf(guess)<2? 0 : basedOn(view[index], guess)).reduce(ADD);
    Pattern.corrstr = maxPt.corrstr;
    Pattern.corr = flattened.map((guess, index) => basedOn(view[index], guess)).reduce(ADD);
    Pattern.incorr = 9-Pattern.corr;
    Pattern.confidence = maxScore-nextScore;
    selectedRot = maxPt.rot;
    Pattern.action = maxPt.action;
    selectedPt = flattened;
    selectedHp = maxPt.hp;
    Pattern.raw = maxPt.raw;
    Pattern.view = maxPt.view;
    selectedVp = maxPt.vp;
    Pattern.score = maxScore;
    if (DEBUG) log("score", maxScore, "confidence", Pattern.confidence, "corr", Pattern.corr, "hardc", Pattern.hardcorr, "pt", maxPt.pt);//, "fn", maxPt.action+""
  }
}
var allPatterns = [];
function clear() {
  allPatterns = [];
}
function adds(raw, action, scorer, presetRot) { // must get a 3x3 arr
  var pt = raw;
  var hp = raw.hp;
  var vp = raw.vp;
  for (let rot = 0; rot < 4; rot++) {
    let view = allVRots[rot];
    allPatterns.push({pt, action, scorer, rot, hp, vp, view, raw});
    if (rot!=4) pt = rotateCW3(pt);
  }
}
function refPt(...args) {
  clear();
  if (Array.isArray(args[0])) {
    if (args[0].length != 3) args[0] = args[0].slice(0,3);
    if (args[0][0].length != 3) args[0] = args[0].map(c=>c.slice(0,3));
    adds(...args);
  }
  else Pattern.add(...args);
  Pattern.choose();
}

/*
is the 2nd param a subset of the 1st param.
guess can be a number (color), or an object ({color:..,ant:..,..})
guess.ant can be "worker", "queen", "enemy", "enemyworker", "enemyqueen" with obvious meanings. Note that "friend" ≠ me
guess.ant.type can be an array, ORing

true - correct!
false - not correct
0 - notqueen doesn't match (aka very bad)

negativesEqual makes this always return true for negative colors, otherwise it treats negatives as regular colors
*/
function basedOn(real, guess, negativesEqual) {
  if (Array.isArray(real)) return real.some(c=>basedOn(c, guess, negativesEqual));
  if (Number.isInteger(guess)) guess = {color:guess};
  if (guess.notqueen && real.ant && real.ant.friend && real.ant.type==5) return 0;
  if (guess.not) {
    var bo = basedOn(real, guess.not, negativesEqual);
    if (bo) return 0;
  } 
  if (guess.color && Math.abs(guess.color) != real.color && !(negativesEqual && guess.color<0)) return false; // 0 handles itself
  if (guess.obstacle !== undefined) {
    if (guess.obstacle && !real.ant && !(food && real.food && !isQueen)) return false;
    if (!guess.obstacle && (real.ant || (food && real.food && !isQueen))) return false;
  }
  if (guess.badobstacle !== undefined) {
    if (guess.badobstacle && !(real.ant && !real.ant.friend) && !(food && real.food && !isQueen)) return false;
    if (!guess.badobstacle && ((real.ant && !real.ant.friend) || (food && real.food && !isQueen))) return false;
  }
  if (guess.ant) {
    if (!real.ant) return false;
    if (guess.ant == "worker"      &&!( real.ant.friend && real.ant.type!=5)) return false;
    if (guess.ant == "queen"       &&!( real.ant.friend && real.ant.type==5)) return false;
    if (guess.ant == "enemyqueen"  &&!(!real.ant.friend && real.ant.type==5)) return false;
    if (guess.ant == "enemyworker" &&!(!real.ant.friend && real.ant.type!=5)) return false;
    if (guess.ant == "friend" && (!real.ant.friend || real.ant.me)) return false;
    if (guess.ant == "enemy"  &&  real.ant.friend) return false;
    if (Number.isInteger(guess.ant) && real.ant.type != guess.ant) return false;
    if (guess.ant.friend !== undefined && guess.ant.friend !== real.ant.friend) return false;
    if (guess.ant.type !== undefined && !(Array.isArray(guess.ant.type)? guess.ant.type.some(c=>c == real.ant.type) : guess.ant.type == real.ant.type)) return false;
    if (guess.ant.food !== undefined && guess.ant.food !== real.ant.food) return false;
  }
  if (guess.food !== undefined && guess.food !== real.food) return false;
  // log("matched");
  return true;
}

function result (action, force) {
  if (!force) if (toReturn !== undefined) return 0;
  var color = action.color;
  var type = action.type;
  var cell = action.cell;
  if (type < 1 || type > 4) return false;
  if (!(cell >= 0 && cell <= 8)) return false;
  if (color < 1 || color > 8) return false;
  if (!color && ((view[cell].ant && cell != 4) || (isQueen? (view[cell].food && type) : (food && view[cell].food)))) return false; // can't walk onto ant, can't spawn on food, can't move to food with food
  if (!isQueen && type) return false;
  if (!isQueen && !color && food && view[cell].food) return false;
  if (isQueen && !food && type) return false;
  if (type && cell==C) return false;
  if (color && type) return false;

  toReturn = action;
  return true;
}

const WH = 1; // white   
const C1 = 6; // green   HW
const C2 = 5; // red     
const C3 = 8; // black   
const C4 = 2; // yellow  HW
const C5 = 4; // cyan    HW
const C6 = 7; // blue    HW
const C7 = 3; // purple  HW
// C1=GR,C2=BL,C4=YL,C5=DK
const ENEMY = {ant:"enemy"};
const foundEnemy = found(ENEMY);
  //-----------------------------------------------------------------------------------------------------------------------------------------------------\\
 //----------------------------------------------------------------------- MAIN CODE ---------------------------------------------------------------------\\
//---------------------------------------------------------------------------------------------------------------------------------------------------------\\

function log(...args) {
  if (!DEBUG) return;
  toLogRaw.push(args);
  // for (let i of args) {
  //   if (i === undefined) i = "undefined";
  //   var res = "";
  //   if (typeof i === 'string') res = i;
  //   else res = JSON.stringify(i);
  //   toLog+= res + " ";
  // }
  // toLog+= "\n";
}
if (DEBUG) {
  var toLog = "";
  var logMyLogs = false;
  var toLogRaw = [];
  log(type, view.map(c=>c.ant? "A"+c.ant.type : c.color));
}

const Ut = 1;
const Dt = 2;
const Ht = 4;
const Uo = {ant:{type:Ut,friend:true}};
const Do = {ant:{type:Dt,friend:true}};
const Ho = {ant:{type:Ht,friend:true}};
const Mo = {ant:{type:[Ut,Dt],friend:true}};
const Fo = {food:1};
const Qo = {ant:{type:5,friend:true}};
const EQo = {ant:{type:5,friend:false}};
const FRIEND = {ant:"friend"};
const OBSTACLE = {obstacle:true};
const FREE = {obstacle:false};
const BADOBSTACLE = {badobstacle:true};
const STARTINGFOOD = 6;
const LESSENFOOD = 160;
const ENDINGFOOD = 160;
const isMiner = type==Ut || type==Dt;
var friendCount = count(FRIEND);
if (isMiner) {
  var Mu = type==Ut? u : d;
  var Md = type==Ut? d : u;
  var Mur = Mu+1;
  var Mul = Mu-1;
  var Mdr = Md+1;
  var Mdl = Md-1;
}

const foodExt = [C3, C7, WH];
const rawRail = [
  [WH,-1,C7,-1], // 43 03 13 23
  [C6,WH,WH,-1], // 42 02 12 22

  [C4,C1,C2,C2],
  [C2,C4,C5,C5],
  [C3,C5,C1,C3],


//[C3,C1,C4,C4],
//[C4,C4,C5,C2],
//[C5,C2,C1,C3],

//[C3,C1,C2,C5],
//[C3,C3,C1,C5],
//[C2,C4,C5,C2],


//[C2,C1,C3,C5], // 41 01 11 21
//[C1,C5,C5,C4], // 40 00 10 20
//[C5,C4,C2,C3], // 41 01 11 21
  [C6,WH,WH,-1], // 42 02 12 22
  [WH,-1,C7,-1]  // 43 03 13 23
]
.map((ln,row)=>(row<2||row>4)? ln.map(c=>({not:{ant:{friend:true, type:[Ht, 5]}},color:c})) : ln); // queen can't be in the top & bottom 2 rows

function section(ln, action, scorer) {
  if (ln > 0) section(-ln, action, scorer);
  var sct = rawRail.slice(ln+2, ln+5);
  var parts;
  if (Math.abs(ln) != 2) {
    parts = [];
    for (let i = 0; i < 4; i++) {
      var cpt = sct.map(([a,b,c,d])=>[a,b,c]);
      cpt.hp = i;
      cpt.vp = ln;
      parts.push(cpt);
      if (i!=4) sct = sct.map(([a,b,c,d])=>[b,c,d,a]);
    }
  } else {
    var o = sct.map(c=>c.slice(0,3));
    o.vp = ln;
    o.hp = 0;
    parts = [o];
  }
  parts.map(c=>adds(c, action, scorer));
}

function sabotage(where) {
  if (on(where, 1)) repair([where], true);
  else color(where, 1);
}


section(0, ()=>{
  if (isMiner) {
    if (on([r,ur,dr], Fo)  ||  on([u,d], Fo) && on([l,ul,dl], Mo)) { // FAKE RAIL
      color(on([dr,d],Fo)? [dr,u,ul] : [dr,d,dl], C7);
    }
    else if ([l,ul,dl].every(c=>on(c,{ant:{}})) && !random4()) move([r,u,d,ur,dr]); // peer pressure
    /* AV */ else if (found(EQo)) sabotage(find(EQo));
    else if (repair()) {
      if (on(r,Mo) && (random4() > 1 || random4() && friendCount > 3)) move([l,Mul,Mu,Mdl,Md]);
      if (on([Mu,Mur], ENEMY)) move([R, D, DR]); // move somewhere away from enemy
      else if (on(r, Qo) && on([l,ul,dl], {ant:{type:[Ut,Dt],food:1,friend:true}})) move([Mu, Mul, l, Mdl]); // make place for miners with food; Possibly stuck
      else if (on(r, Qo)) move([Mu, Mul]); // don't do stupid things around queen
      else if (on(l, Qo) && !foundEnemy) move([Mul, Mdl, Mu, Md]); //.. I've done stupid things around queen
      else if (on([Mu,Mur], OBSTACLE)) { // up is blocked :/
        if (random4()) move(on(Mu, FRIEND)? [Mur, r] : r);
        else move([r, Mul, Md, Mul, l, Mdl]);
      }
      else move([Mu, r, Mur, Md, Mdr]); // move along
    }
  } else if (isQueen) {
    var HM = Pattern.view.map(c=>+basedOn(c, Ho));
    var helperRows = [HM.slice(0,3),HM.slice(6,9)].map(c=>c.lastIndexOf(1)).map((c,i) => (c==0 && on(i==0? u : d, OBSTACLE)) ? -1 : c);
    var minH = Math.min(helperRows[0],helperRows[1]);
    var maxH = Math.max(helperRows[0],helperRows[1]);
    if (on(r, FRIEND) && [ur,dr].every(c=>on(c, ENEMY))) move([l,ul,dl]);
    if (found(EQo)) { // vampire?
      move(random4()%2? [ur,dr] : [dr,ur]);
      var eQueenRel = (findRel(EQo)-rp)%3;
      if (eQueenRel == 0) move(r,ur,dr);
      spawn(Mu, [u,d,r,ur,dr]);
    }
    if (foundEnemy) // spawn helpers against enemies
      if (food && minH == -1 && count(Ho) < 2) {
        if (helperRows[0] == -1) spawn([u,ur,ul],Ht);
        else                     spawn([d,dr,dl],Ht);
      }
    if ([r,ur,dr].every(c=>on(c, ENEMY))) move([ul,dl,l,u,d]); // OH GOD NO WHY
    if ((minH == -1 || maxH == 2) && on(r, [ENEMY,Ho]) && Pattern.incorr < 2 && count({ant:{}})-1 != count(Ho))
      move(on(ur, ENEMY)? [d,u,dr,ur,ul,dl,l] : [u,d,ur,dr,ul,dl,l]); // initialize transporting around enemy
    if ((!random4() && on(l, OBSTACLE) && on([ul, dl], OBSTACLE)) && Pattern.corr >= 7) move(r); // move forward sometimes if left is 2/3s full
    else if ([r,ur,dr].every(c=>c.ant && !c.ant.friend)) move([l,ul,dl]);
    else if (food && minH > 0 && (
        count(Mo) == 0 && selectedHp != 1 && Pattern.corr != 9 && food < LESSENFOOD
      ||
        //Pattern.corr === 9 && [u,d].every(c=>on(c,Ho)) && selectedHp === 1 && food >= LESSENFOOD && food < ENDINGFOOD && random4() < 2
        Pattern.corr === 9 && selectedHp == 0 && count(Mo) === 0 && food >= LESSENFOOD && food < ENDINGFOOD && random4() < 2
      )) { // spawn miners
      if (random4()%2) spawn([u,ul], Ut);
      else             spawn([d,dl], Dt);
    } else if (repair()) {
      if (food && minH == -1 && count(Ho) < 2) { // spawn helpers
        if (helperRows[0] == -1) spawn([u,ur,ul],Ht);
        else                     spawn([d,dr,dl],Ht);
      }
      else if (selectedHp != 1  ||  selectedHp==1 && /*(*/(maxH==2 || minH == -1 && helperRows.includes(2)) && (!random4() || food < LESSENFOOD || found(Mo))  ||  foundEnemy) move(r); // move forwards
      else if (on(ul, Do) && on(dl,Uo) && on(l, {ant:{}})) move(r); // miners are in wrong places
    }
  } else { // helper
    var repaired = repair();
    var queenRel = (findRel(Qo)-rp)%3;
    var dir = queenRel==0? 0 : 1;
    if (repair()) {
      if (on(r, EQo) && [u,d,ur,dr].map(c=>on(c, ENEMY)? 1 : 0).reduce(ADD) >= 3) move(c); // protect the queen from the evils ahead
      else if (on(r, Qo)) move([u,d,ur,dr,ul,dl,l]);
      else move((on([d,dr,dl], Ho)? [u+dir,d+dir] : [d+dir,u+dir]).concat([u+(1-dir), d+(1-dir)]), !random4());
    }
  }
})

section(1, ()=>{
  const A = selectedVp > 0? d : u; // away
  const I = selectedVp > 0? u : d; // in
  const AR = A+1;
  const AL = A-1;
  const IR = I+1;
  const IL = I-1;

  if (isMiner) {
    var queenRel = (findRel(Qo)-rp)%3;
    if (on([r,IR], Fo)) color([r,IR, I], C7); // FAKE RAIL
    else if ([l,IL].every(c=>on(c,{ant:{}})) && !random4()) move([r,IR]); // peer pressure
    /* AV */ else if (found(EQo)) sabotage(find(EQo));
    else if ((found(EQo) && random4() && Pattern.dist <= 1 && on(find(EQo), 1)) || repair()) {
      if (on(I, Qo)) move(l); // what am I doing here?
      else if (A == Mu) { // my dir!
        if (!food && selectedHp == 0 && (on(r,Ho) && on(IR, Qo)  ||  count(Mo) >= 6)) move(A); // move out!
        else if (on(IR,Qo) && on([l,IL], {ant:{type:[Mu,Md],friend:true,food:1}})) move(C); // waiting in line :D
        else if (on(IR,Qo)) move(C); // waiting in line :D
        else if (random4()) move([r, I, IR]);
        else move([r, I, IR, l, IL]);
      } else { // not my dir
        // TODO fix \\ if (selectedHp == 0 && count(Mo) >= 6 && food) move(A); // fake rail escape
        if (random4()) {
          move([I, IR, IL, l]);
        } else {
          move([r, I, IR, IL, l]);
        }
      }
    }
  } else if (isQueen) {
    if (found(EQo)) { // vampire?
      var eQueenRel = (findRel(EQo)-rp)%3;
      if (eQueenRel==0) move(r, IR);
      spawn(Mu, [r,IR]);
      spawn(Md, I);
    }
    /* AV */ if (food > 70 && (
      [IR,IL,I,l,r].every(c=>on(c,ENEMY)) // completely encased
      || on(IR, EQo) && [r,I].every(c=>on(c, ENEMY)) // getting leeched
      || on(I, EQo) && [r,l,IL,IR].map(c=>get(c)).map(c=>c.ant? (c.ant.friend? 1 : -1) : 0).reduce(ADD) < 0 // leeched
    )) move([A,AR,AL]); // BAD NEWS COMPLETELY DEAD
    if (!random4() || found(EQo) || repair())
      move(random4()? [IR,r,I,l] : [IR,r,I]);
  } else { // helper
    var queenRel = (findRel(Qo)-rp)%3;
    /* AV */ if (on(r,Qo) && on([I,IR], EQo)) move([IR,I,l,IL]);
    if (on(l, Qo)) { if (!random4() || repair()) move(r) } // queen's transporting
    if (on(I, Qo) && on(IR, {ant:"enemyworker"})) { if (!random4() || repair()) move(r) } // queen needs to transport
    // what was this? if ([l,IL,I].every(c=>on(c,OBSTACLE)) && (count(ENEMY) > 1 || find(EQo)) && !random4()) move([r,ur]);
    if ((selectedVp < 0? /...[#-W]{6}/ : /[#-W]{6}.../).test(Pattern.corrstr) && queenRel == 2 && count(Ho) == 1) move(r); // move forward without repairing
    if (!random4() && queenRel == 1 && selectedHp == 1 && on(AL, {ant:{}})) move(r); // something is out; don't repair
    else if (repair([r,l,A,AR,AL])) {
      if (on(r, ENEMY) && on(I, Qo) && [l,IL].every(c=>on(c,FRIEND))) move(IR); // protect from vampire
      if (on(r, ENEMY) && on(IL, Qo) && [l,IR].every(c=>on(c,FRIEND))) move(I);
      if (on(r, ENEMY) && !get(r).ant.food && on(I, Qo)) move(IR);
      if (queenRel == 1 && selectedHp == 1 && on(AL, {ant:{}})) move(r); // something is out
      else if (on([l,r], Ho)) { // move to the other side
        if (found(Qo)) move([I]); // TODO integrate ,IL,IR
        else move([l,r]);
      }
      else if (queenRel == 2) move(r); // move forward
    }
  }
}, (pscore, pt, corrects, falseN, match) => {
  if (match(".?(...)?@@.@@.*") && !foundEnemy) {
    if (!match(pt.vp>0? ".?@@.@@.*" : ".?...@@.@@.*")) pscore/=2;
  }
  return pscore;
})

if (isMiner) {
  section(2, () => {
    const A = selectedVp > 0? d : u; // away
    const I = selectedVp > 0? u : d; // in
    if (on(A,OBSTACLE)) move(I);
    else if (repair()) move(food? I: Mu);
  }, (pscore, pt, corrects, falseN, match) => match(pt.vp>0? "@@@.@...." : "....@.@@@")? match("@@@@@@@@@")? 100 : ((pt.vp>0) == (type==Dt)? 13 : 10) : 0);
  if (type==Dt) foodExt.reverse();
  if (!found(Ho) && !found(Qo)) {
    var lns = [rawRail[0], rawRail[1]].map(c=>c.slice(0,3));
    [[lns[0],lns[1],lns[0]], [lns[1],lns[0],lns[1]]].map(c=>{
      adds(c, () => {
        var onL;
        if (!food && ((onL = on(l, Fo)) || on(r, Fo))) {
          var foodpt = Pattern.raw.map((ln, i) => [ln[0], foodExt[i], ln[2]]);
          refPt(foodpt,undefined,undefined,selectedRot);
          if (repair()) move(onL? l : r);
        }
        else if (repair([l,r,ul,ur,dl,dr], on([Mul, Mur, Mdl, Mdr, l, r], {ant:{friend:true,type:[Ut,Dt],food:1}}) ||  on([Mu, Md], Mo))) {
          move(food? [Md, Mu] : [Mu, Md]);
        }
      }, (pscore, pt, corrects, falseN, match) => {
        var score = 0;
        var dMatch = match("...@.@@@@");
        var uMatch = match("@.@@.@...");
             if ((type==Ut ^ food) && dMatch) score = 15;
        else if ((type==Dt ^ food) && uMatch) score = 15;
        else if (uMatch || dMatch) score = 6;
        if ([0,2,3,5,6,8].some(c=>basedOn(pt.view[c], FRIEND) && !pt.view[c].ant.food)) score = 0;
        return score;
      });
      if (food) {
        var extp = c.map((ln, i) => [ln[0], foodExt[i], ln[2]]);
        [extp.map(([a,b,c])=>[0,a,b]), extp.map(([a,b,c])=>[b,c,0])].forEach((pt,i) => adds(pt, () => {
          move(i? l : r);
        }, (pscore, pt, corrects, falseN, match) => match("@@@@@@@@@")? 100 : 0));
      }
    });
  }
}

Pattern.choose();
var confident = ((Pattern.confidence >= 1 && (Pattern.score > 4 || Pattern.corr >= 4)) || (Pattern.score >= 9 && Pattern.confidence > 0.05)); // && (selectedHp !=  || !found(Qo));
var failAction = () => {
  if (foundEnemy) {
    log(view);
    log("dead around enemy :/");
    logMyLogs = true;
  }
  if (isQueen) {
    if (found(EQo)) {
      move([8-(find(EQo)-rp) + rp]);
      move(random4()%2? U : UR);
    }
    if (foundEnemy) move(random4()%2? U : UR);
  } else {
    // if (!found(Qo) && found(Fo)) move(find(Fo));
    var enemyPlace = find(ENEMY);
    if (enemyPlace !== -1) color(enemyPlace, get(enemyPlace).color==1? C3 : WH);
  }
}
if (!confident) Pattern.action = failAction;

if (isMiner) {
  if ((Pattern.hardcorr >= 4 || Pattern.score > 5) && confident) Pattern.action();
  else {
    failAction();
  }
} else if (isQueen) {
  if ((Pattern.hardcorr >= 6 || food > STARTINGFOOD+2 || friendCount>1 || found(Mo) || Pattern.score > 6 || (false)) && confident) Pattern.action();
  else if (food >= STARTINGFOOD && friendCount == 1) {
    clear();
    Pattern.add([[1,{ant:Ho.ant,color:1},1],
                 [1,1,1],
                 [1,1,1]], ()=>spawn([ur,ul],Ht));
    Pattern.add([[1,1,{ant:Ho.ant,color:1}],
                 [1,1,1],
                 [1,1,1]], ()=>spawn([ur,u],Ht));
    Pattern.choose();
    if (repair()) Pattern.action();
  } else if (food == 0 && friendCount == 0) { // diagonal search
    if (found(Fo)) {
      move(find(Fo));
    } else {
      clear();
      Pattern.add([[WH,WH,WH],
                   [WH,C1,WH],
                   [C1,WH,WH]], ()=>move(ur));
      Pattern.add([[WH,WH,WH],
                   [WH,WH,WH],
                   [C1,WH,WH]], ()=>color(C, C1));
      Pattern.add([[WH,WH,WH],[WH,WH,WH],[WH,WH,WH]], ()=>color(DL, C1));
      Pattern.choose();
      if (Pattern.corr == 9) Pattern.action();
      else move(random4()? [DL,UL,DR,UL] : [D,L,U,R]);
    }
  } else if (food == 1 && friendCount == 0) spawn([U,L,D,R,UL,DL,UR,DR], Ht);
  else if (friendCount == 1) lightSpeed();
  else if (friendCount > 0) {
    var pt = new Pattern(rawRail).select(0,2,4,3).rotate(L).rotate(L).pt;
    pt[1][2] = {color:pt[1][2], ant:{type:Ht, friend:true}};
    refPt(pt);
    repair([c,u,d,ur,dr]);
  } // TODO wtf to do after this
  else Pattern.action(); // eh fuck it
} else if (type == Ht) {
  if (confident && (Pattern.score >= 4 || Pattern.hardcorr >= 5 || friendCount>1)) Pattern.action();
  else if (found(Qo)) lightSpeed();
  else if (Pattern.hardcorr >= 3 && confident) repair();
}

function lightSpeed() {
  var other = find(isQueen? Ho : Qo);
  var orth = other%2;
  if (isQueen || (view[other].ant.food < STARTINGFOOD && count(Ho) == 1)) { // LS
    if (orth && found(Fo)) { // grab easy food
      var fp = find(Fo);
      if (sees(other, fp)) move(fp);
      else {
        refPt([[0,FRIEND,0],
                     [0,0,0],
                     [0,0,0]]);
        move(l);
      }
    }
    clear();
    // Pattern.when(U,find(FRIEND), ()=>isQueen? move(ul) : move(ur)); when I'm not lazy imma make this a replacement of the below
    Pattern.add([[0,FRIEND,0],
                 [0,0,0],
                 [0,0,0]], ()=>isQueen? move(ul) : move(ur));
    Pattern.add([[0,0,FRIEND],
                 [0,0,0],
                 [0,0,0]], ()=>move(u));
    Pattern.choose();
    Pattern.action();
  }
}

if (DEBUG) log("END", type, view.map(c=>c.ant? "A"+c.ant.type : c.color));
if (DEBUG && logMyLogs) {
  //for (let i = 0; i < toLog.length; i+=800)
  //  console.log(toLog.substring(i,i+800));
  for (let i of toLogRaw) console.log(...i);
}
if (toReturn) return toReturn;
else return {cell:4};

이전에는 이것이 광부에서 광부 였지만 (개정 내역 참조) 더 나은 성능으로 슬라이딩 광부로 변경되었으며 MoaR이 다른 항목 인 경우 성공을 방해 할 수있었습니다.


이번에는 리더 보드에서 다시 처음으로 ...
trichoplax

14

글라이더

글라이더 작동글라이더가 좌회전글라이더 우회전

//console.log(JSON.stringify(view))
var TRAIL = 6;
var SPAWN = 3;
var IDLE = 4;
var FOOD_THRESHOLD = 150;
var SPAWN_MIN = 3;
var HIGHWAY_COLORS = [7,6,4,2,3];
var HIGHWAY_THRESHOLD = 70;
var ret = {cell:4};
if(isOnHighway()) {
    var cont = true;
    //== Make best guess to if in a glider formation ==//
    if(view[4].ant.type == 5) {
        if((findWorker(1) >= 0 && findWorker(4) >= 0) || view[4].ant.food < HIGHWAY_THRESHOLD) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 4) {
        if(findWorker(1) >= 0 && findWorker(5) >= 0) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 3) {
        if(findWorker(2) >= 0 && findWorker(5) >= 0) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 2) {
        if(findWorker(5) < 0) {
            var pos3 = findWorker(3);
            if(pos3 >= 0 && view[pos3].ant.food == 0) {
                cont = false;
            }
        }
        else if(findWorker(3) >= 0 || (findWorker(1) >= 0 && view[findWorker(5)].color == SPAWN))
            cont = false;
    }
    else if(view[4].ant.type == 1) {
        if(findWorker(5) < 0) {
            var pos4 = findWorker(4);
            if(pos4 >= 0 && view[pos4].ant.food == 0) {
                cont = false;
            }
        }
        else if(!isHighwayCenter())
            cont = false;
    }
    if(findWorker(5) >= 0) {
        for(var i=0;i<9;i++) {
            if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                if(view[i].ant.food > 10 || view[i].ant.food == 0)
                    cont = true;
                else
                    cont = false;
            }
        }
    }
    //== End guesswork ==//
    if(cont) {
        ret = highwayRobbery();
        if(view[4].ant.type == 1) {
            //try to repair
            var curIndex = HIGHWAY_COLORS.indexOf(view[4].color);
            var prvCol = HIGHWAY_COLORS[(curIndex+1)%HIGHWAY_COLORS.length];
            var nxtCol1 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-1)%HIGHWAY_COLORS.length];
            var nxtCol2 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-2)%HIGHWAY_COLORS.length];
            var nxtCol3 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-3)%HIGHWAY_COLORS.length];
            var prevAt = -1;
            for(var i=0;i<9;i++) {
                if(i%2 == 1 && view[i].color == prvCol && view[deRotate(i,1)].color == nxtCol1 && view[deRotate(i,-1)].color == nxtCol1) prevAt = i;
            }
            if(prevAt >= 0) {
                // yep, brute force it. Because I'm lazy.
                var goNxt = 8-prevAt;
                if(view[deRotate(goNxt,1)].color == nxtCol3 && view[deRotate(goNxt,-1)].color == prvCol) ret = {cell:goNxt};
                else if(view[deRotate(goNxt,1)].color == prvCol && view[deRotate(goNxt,-1)].color == nxtCol3) ret = {cell:goNxt};
                else if(view[goNxt].color != nxtCol1) ret = {cell:goNxt,color:nxtCol1};
                else if(view[deRotate(goNxt,2)].color != nxtCol2) ret = {cell:deRotate(goNxt,2),color:nxtCol2};
                else if(view[deRotate(goNxt,-2)].color != nxtCol2) ret = {cell:deRotate(goNxt,-2),color:nxtCol2};
                else if(view[deRotate(goNxt,1)].color != nxtCol3) ret = {cell:deRotate(goNxt,1),color:nxtCol3};
                else if(view[deRotate(goNxt,-1)].color != nxtCol3) ret = {cell:deRotate(goNxt,-1),color:nxtCol3};
                else ret = {cell:goNxt};
                ret = sanityCheck(ret);
                return ret;
            }
        }
        if(view[4].ant.type == 5 && isHighwayCenter()) {
            if(ret.cell >= 0) {
                ret = {cell:8-ret.cell};
                if(view[4].color == SPAWN && (view[4].ant.food > 90 || view[4].ant.food % 7 == 0) && getHighestWorker() == 0 && (view[4].ant.food < 140 || view[4].ant.food % 9 == 0) && view[0].color == 2 && view[4].ant.food > 50 && view[4].ant.food < 200) {
            //fine
                    if(view[4].ant.food % 10 < 5)
                        ret = {cell:deRotate(ret.cell,3),type:3};
                }
                if(view[ret.cell].ant != null && !view[ret.cell].ant.friend && view[ret.cell].ant.food == 0 && view[4].ant.food > 0) {
                    if(view[deRotate(ret.cell,1)].ant == null)
                        ret = {cell:deRotate(ret.cell,1),type:3};
                    if(view[deRotate(ret.cell,-1)].ant == null)
                        ret = {cell:deRotate(ret.cell,1),type:3};
                }
            }
            for(var i=0;i<9;i++) {
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                    ret = {cell:8-i};
                }
            }
        }
        if(ret.cell >= 0) {
            for(var i=0;i<9;i++) {
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                    var rr = basicHighwayMove();
                    if(rr.cell >= 0 && view[4].ant.type != 5)
                        ret = {cell:deRotate(rr.cell,-2)};
                }
            }
            if(view[ret.cell].ant != null) {
                var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
                var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
                for(var i=0;i<9;i++) {
                    if(view[i].color == nextMove) {
                        if(view[i].ant == null) {
                            ret = {cell:i};
                            break;
                        }
                    }
                }
                if(view[4].ant.type == 5) ret = {cell:8-ret.cell};
            }
        }
        if(view[4].ant.type == 5) {
            var foodedEnemy = false;
            for(var i=0;i<9;i++) {
                if(getNumWorkers(3) >= 2) break;
                if(i != 4 && view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 25) {
                    if(view[deRotate(i,1)].ant == null) {
                        ret = {cell:deRotate(i,1),type:3};
                    }
                    else if(view[deRotate(i,-1)].ant == null) {
                        ret = {cell:deRotate(i,-1),type:3};
                    }
                    else if(i%2 == 1 && view[deRotate(i,2)].ant == null) {
                        ret = {cell:deRotate(i,2),type:3};
                    }
                    else if(i%2 == 1 && view[deRotate(i,-2)].ant == null) {
                        ret = {cell:deRotate(i,-2),type:3};
                    }
                }
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 3 && view[8-i].ant == null) {
                    if(i == ret.cell) {
                        ret = {cell:deRotate(i,1)}
                    }
                    else {
                        return {cell:8-i};
                    }
                }
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.food == 0) {
                    foodedEnemy = true;
                }
            }
        }
        var numAnts = 0;
        for(var i=0;i<9;i++) {
            if(view[i].ant != null)
                numAnts++;
        }
        if(numAnts > 2 && sanityCheck(ret).cell == 4) {
            ret = {cell:findOpenSpace(0,1)};
        }
        if(view[4].ant.type == 3) {
            if(getNumWorkers(5) > 0) {
                for(var i=0;i<9;i++) {
                    if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                        ret = {cell:4};
                    }
                }
            }
        }
        if(view[4].ant.type == 4 && getNumWorkers(1) && isHighwayCenter()) {
            var workerPos = findWorker(1);
            for(var i=0;i<9;i++) {
                if(!areAdjacent(i,workerPos)) ret = {cell:i};
            }
        }
        if(ret.cell == -1) {
            if(isHighwayCenter()) {
                for(var i=0;i<9;i++) {
                    var p1 = deRotate(i,3);
                    var p2 = deRotate(i,-3);
                    if(view[i].color == view[p1].color && view[i].color == view[p2].color) {
                        ret = {cell:8-i};
                    }
                }
                if(view[4].ant.type == 1 || view[4].ant.type == 5) {
                    ret = {cell:8-ret.cell};
                }
            }
        }
        if(ret.cell >= 0)
            return sanityCheck(ret);
    }
}

switch(view[4].ant.type) {
    case 5:
        ret = doQueen();
        break;
    case 1:
    case 2:
        ret = doSweep();
        break;
    case 3:
    case 4:
        ret = doGuide();
        break;
    default:
        break;
}
//basic sanity check
ret = sanityCheck(ret);
return ret;

function sanityCheck(ret) {
    if(!ret || ret.cell < 0 || ret.cell > 8) {
        return {cell:4};
    }
    if(ret.color) {
        return ret;
    }
    if((ret.cell != 4 && view[ret.cell].ant != null) || (view[ret.cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) {
        return {cell:4};
    }
    if(ret.type && (view[ret.cell].ant != null || view[ret.cell].food > 0 || view[4].ant.food == 0 || view[4].ant.type < 5)) {
        return {cell:4};
    }
    return ret;
}

function doQueen() {
    if((view[4].ant.food == SPAWN_MIN || (view[4].ant.food >= SPAWN_MIN && view[4].ant.food < FOOD_THRESHOLD && (view[4].ant.food % 3 == 1 || isOnHighway()))) && getHighestWorker() <= 1 ) {
        //prep for first ant
        var s0 = view[0].ant;
        var s1 = view[1].ant;
        var s2 = view[2].ant;
        var s3 = view[3].ant;
        var s5 = view[5].ant;
        var s6 = view[6].ant;
        var s7 = view[7].ant;
        var s8 = view[8].ant;
        var nullCount = 0 + (s0 == null?1:0) + (s1 == null?1:0) + (s2 == null?1:0) + (s3 == null?1:0) + (s5 == null?1:0) + (s6 == null?1:0) + (s7 == null?1:0) + (s8 == null?1:0);
        var nullCount2 = 0 + (s0 == null || s0.friend?1:0) + (s1 == null || s1.friend?1:0) + (s2 == null || s2.friend?1:0) + (s3 == null || s3.friend?1:0) + (s5 == null || s5.friend?1:0) + (s6 == null || s6.friend?1:0) + (s7 == null || s7.friend?1:0) + (s8 == null || s8.friend?1:0);
        if(nullCount >= 7 && nullCount2 >= 8 && view[1].food == 0 && view[3].food == 0 && view[5].food == 0 && view[7].food == 0) {
            var high = getHighestWorker();
            if (high <= 1 && view[4].color != SPAWN && !isOnHighway()) {
                // 50% chance of delaying the respawn by 1 additional move away from where we exploded
                // reduces the chance of a second, immediate explosion
                var pos1 = findWorker(1);
                if(findFirstTrail() < 2 && view[4].ant.food > SPAWN_MIN+1 && pos1 < 0) return foreverAlone();
                if(pos1 >= 0) {
                    var space = deRotate(pos1,2);
                    if(view[space].ant != null) return {cell:findOpenSpace(0,1)};
                }
                return {cell:4,color:SPAWN};
            }
            //spawn first ant
            else if(view[4].color == SPAWN) {
                var pos1 = findWorker(1);
                if(pos1 < 0)  {
                    pos1 = findFirstTrail();
                    if(pos1 % 2 == 0) pos1 = deRotate(pos1,1);
                    else pos1 = deRotate(pos1,4);
                }
                var space = findOpenSpace(pos1,2);
                var high = getHighestWorker();
                if(space < 0) return {cell:4,color:TRAIL}
                if(high == 0) { //no workers
                    return {cell:space,type:1};
                }
                else if(high < 4) { //1 worker of type:high
                    return {cell:space,type:high+1};
                }
                else { //1 worker of type 4
                    //we have all workers, skip!
                }
            }
        }
        else {
            return foreverAlone();
        }
    }
    else if(view[4].ant.food == 1 && getHighestWorker() == 0 ) {
        var space = findOpenSpace(1,2);
        return {cell:space,type:1};
    }
    else if(view[4].ant.food >= 1 && getHighestWorker() < 4 && findWorker(1) >= 0) {
        //spawn remaining ants
        if(view[4].color == SPAWN && !isHighwayCenter()) {
            var pos1 = findWorker(getHighestWorker());
            var space = deRotate(pos1,2);
            var high = getHighestWorker();
            if(space < 0 || view[space].ant != null) return {cell:findOpenSpace(0,1)};
            if(high == 0) { //no workers
                return {cell:space,type:1};
            }
            else if(high < 4) { //1 worker of type:high
                return {cell:space,type:high+1};
            }
            else { //1 worker of type 4
                //we have all workers, skip!
            }
        }
    }
    if(view[4].color == SPAWN && getNumWorkers(3) == 1 && getNumWorkers(4) == 1) {
        var one = getNumWorkers(1);
        var two = getNumWorkers(2);
        if((one ^ two) == 1 && (findWorker(1) % 2 == 0 || findWorker(2) % 2 == 0))
            return {cell:4,color:1};
    }
    if(getNumWorkers(1) == 0 && getNumWorkers(2) == 0) {
        if(getNumWorkers(4) == 1 && getNumWorkers(3) == 0) {
            var pos4 = findWorker(4);
            if(view[deRotate(pos4,1)].ant == null && view[deRotate(pos4,2)].ant == null && findWorker(4) % 2 == 1) {
                //finish rotate with only one glider arm
                return {cell:4};
            }
        }
        return foreverAlone();
    }
    else if(getNumWorkers(1) >= 1 && getNumWorkers(2) >= 1 && getNumWorkers(3) >= 1 && getNumWorkers(4) >= 1) {
        if(view[4].color != 2 && findWorker(1)%2 == 1 && findWorker(2)%2 == 1) {
            return {cell:4,color:TRAIL};
        }
        //move diagonally
        var pos = findWorker(4);
        pos = deRotate(pos,1);
        var checkpos = view[deRotate(pos,4)];
        if(checkpos.ant != null && checkpos.ant.friend) {
            if(checkpos.ant.type == 2)
                return {cell:4};
            if(checkpos.ant.type == 1)
                return {cell:4};
        }
        if(view[pos].ant) return {cell:4,color:1};
        return {cell:pos};
    }
    else {
        var pos = findWorker(4);
        if(pos < 0) {
            //if gliding along with only a buddy
            pos = findWorker(1);
            if(pos >= 0 && view[deRotate(pos,2)].food > 0 && view[deRotate(pos,1)].food == 0) {
                return {cell:4};
            }
        }
        if(pos < 0) {
            var s1 = view[1].ant;
            var s3 = view[3].ant;
            var s5 = view[5].ant;
            var s7 = view[7].ant;
            //return {cell:999}
            if(s1 == null) {
                if(s3 == null) {
                    return {cell:0};
                }
                if(s5 == null) {
                    return {cell:2};
                }
            }
            if(s7 == null) {
                if(s3 == null) {
                    return {cell:6};
                }
                if(s5 == null) {
                    return {cell:8};
                }
            }
            return {cell:4};
        }
        pos = deRotate(pos,1);
        var checkpos1 = view[pos];
        for(var i=0;i<9;i++) {
            if(i != 4 && view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 2) {
                if(i%2==0) {
                    if(view[deRotate(i,1)].ant == null) return {cell:deRotate(i,1),type:3};
                    if(view[deRotate(i,-1)].ant == null) return {cell:deRotate(i,-1),type:3};
                }
                else {
                    if(view[deRotate(i,1)].ant == null) return {cell:deRotate(i,1),type:3};
                    if(view[deRotate(i,-1)].ant == null) return {cell:deRotate(i,-1),type:3};
                    if(view[deRotate(i,2)].ant == null) return {cell:deRotate(i,2),type:3};
                    if(view[deRotate(i,-2)].ant == null) return {cell:deRotate(i,-2),type:3};
                }
                return {cell:4};
            }
        }
        if(checkpos1.ant != null && view[deRotate(pos,1)].ant != null && !view[deRotate(pos,1)].ant.friend) {
            return foreverAlone();
        }

        var checkpos2 = view[deRotate(pos,4)];
        var checkpos3 = view[deRotate(checkpos,1)];
        if(checkpos1.ant != null && checkpos1.ant.friend && checkpos1.ant.type == 1 && checkpos2.ant != null && checkpos2.ant.friend && checkpos2.ant.type == 2 && checkpos3.ant != null && checkpos3.ant.friend && checkpos3.ant.type == 3) {
            //move out of spawn orientation
            return {cell:4};
        }
        if(view[pos].ant != null) {
            if(checkpos2.ant == null && checkpos1.ant == null) {
                return {cell:8-pos};
            }
            if(!view[pos].ant.friend) {
                return foreverAlone();
            }
            if(view[4].color == TRAIL) return foreverAlone();
            return {cell:4,color:TRAIL};
        }
        if(8 - findWorker(3) == findWorker(4)) {
            //finish rotate to the right
            return {cell:4};
        }
        if((view[deRotate(pos,1)].food > 0 || view[deRotate(pos,2)].food > 0) && view[deRotate(pos,1)].ant == null && view[4].color != TRAIL) {
            if(findWorker(1) < 0 || view[deRotate(findWorker(1),1)].food == 0) {
                return {cell:4};
            }
        }
        return {cell:pos};
    }
    return {cell:100+view[4].ant.type}; //oh god
}

//guides sit next to the queen
function doGuide() {
    var queenPos = findWorker(5);
    var ty = view[4].ant.type==3?2:1;
    var dir = view[4].ant.type==3?1:-1;
    if(queenPos >= 0 && queenPos%2 == 1 && view[queenPos].color == SPAWN) {
        if(view[deRotate(queenPos,dir*2)].ant == null) {
            return {cell:4};
        }
    }
    if(queenPos < 0 || findWorker(ty) < 0) {
        if(findWorker(ty) >= 0 && view[0].color != IDLE) return {cell:0,color:IDLE}
        return firebreak();
    }
    var checkpos = view[deRotate(queenPos,-2*dir)];
    if(view[4].ant.type==4 && checkpos.ant != null && checkpos.ant.friend && checkpos.ant.type == 1) {
        //attempt rotate
        return {cell:deRotate(queenPos,-dir)};
    }
    checkpos = view[deRotate(queenPos,4)];
    if(checkpos.ant != null && checkpos.ant.friend && checkpos.ant.type == ty) {
        //attempt rotate
        if(getNumWorkers(ty) == 1) {
            return {cell:4};
        }
    }
    var pos = deRotate(queenPos,dir);
    if(pos >= 0 && view[4].ant.type==3 && findWorker(4) < 0) {
        //wait for rotate
        if(view[4].color == TRAIL) {
            return {cell:4};
        }
    }
    if(pos >= 0 && findWorker(2) >= 0 && view[deRotate(findWorker(2),1)].ant != null) {
        //rotate
        return {cell:4,color:TRAIL};
    }
    if(pos < 0) pos = 4;
    else if(view[pos].ant != null) return {cell:deRotate(queenPos,4)};
    if(pos == 4 && view[queenPos].color == TRAIL) return {cell:queenPos,color:1};
    return {cell:pos};
}

//sweepers sit next to guides
function doSweep() {
    var queenPos = findWorker(5);
    var followType = view[4].ant.type==1?4:3;
    var pos = findWorker(followType);
    if(pos % 2 == 0 && getNumWorkers(followType) > 1) {
        //if there's more than one worker #4, we want to use the best one
        for(var i=pos+1;i<9;i++) {
            if(i != 4 && view[i].ant != null) {
                if(view[i].ant.friend && view[i].ant.type == followType) {
                    pos = i;
                    break;
                }
            }
        }
    }
    if(queenPos >= 0 && queenPos%2 == 1 && view[queenPos].color == SPAWN) {
        var p = findWorker(view[4].ant.type);
        if(p >= 0 && (deRotate(p,1) == queenPos || deRotate(p,-1) == queenPos)) {
            return {cell:8-queenPos};
        }
        return {cell:4};
    }
    if(queenPos >= 0 && pos < 0) {
        //if Worker #1 is the only ant besides the queen:
        //TODO
    //good
        if(view[queenPos].ant.food <= SPAWN_MIN || !(view[queenPos].ant.food < FOOD_THRESHOLD && view[queenPos].ant.food % 3 == 1 && !isOnHighway())) {
            var go = deRotate(queenPos,-1);
            if((view[deRotate(queenPos,-2)].food > 0 || view[deRotate(queenPos,-3)].food > 0 || (queenPos %2 == 1 && view[deRotate(queenPos,-3)].food > 0)) && view[go].food == 0) {
                go = deRotate(queenPos,2);
                //return {cell:4};
            }
            return {cell:go};
        }
        else if(view[queenPos].ant.food < FOOD_THRESHOLD && view[queenPos].ant.food % 3 == 1) {
            return {cell:4};
        }
    }
    if(queenPos >= 0) {
        var dir = view[4].ant.type==1?1:-1;
        //var checkpos = view[deRotate(pos,-dir)];
        var moveTo = deRotate(pos,dir);
        if(moveTo >= 0 && view[moveTo].ant != null && view[moveTo].ant.friend && view[moveTo].ant.type == 5) {
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type == 2 && findWorker(1) < 0 && view[queenPos].color != TRAIL) {
            moveTo = 4;
        }
        return {cell:moveTo};
    }
    else {
        if(pos < 0) return {cell:4}; //firebreak();
        var dir = view[4].ant.type==1?-1:1;
        var moveTo = deRotate(pos,dir);
        if(view[4].ant.food > 0 && view[moveTo].food > 0) {
            //have food, attempt to give to queen
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type==1 && pos >= 0 && (view[deRotate(pos,dir*2)].food > 0 || view[deRotate(pos,dir*3)].food > 0)) {
            //attempt rotate
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type==2 && pos >= 0 && (view[deRotate(pos,dir*2)].food > 0 || view[deRotate(pos,dir*3)].food > 0)) {
            //attempt rotate
            moveTo = deRotate(pos,-dir);
        }
        if(moveTo >= 0 && view[moveTo].ant != null && view[moveTo].ant.type == 5) {
            if(view[moveTo].ant.friend)
                moveTo = deRotate(moveTo,dir*2);
            else
                moveTo = deRotate(pos,-dir);
        }
        return {cell:moveTo};
    }
    return {cell:100+view[4].ant.type};//oh god
}

function foreverAlone() {
    var s0 = view[0].ant;
    var s1 = view[1].ant;
    var s2 = view[2].ant;
    var s3 = view[3].ant;
    var s5 = view[5].ant;
    var s6 = view[6].ant;
    var s7 = view[7].ant;
    var s8 = view[8].ant;
    //good
    if(!(s0 == null && s1 == null && s2 == null && s3 == null && s5 == null && s6 == null && s7 == null && s8 == null) && view[4].color == TRAIL) {
        if (view[0].color == TRAIL && !view[8].ant && view[8].color != TRAIL) return {cell: 8};
        else if (view[2].color == TRAIL && !view[6].ant && view[6].color != TRAIL) return {cell: 6};
        else if (view[6].color == TRAIL && !view[2].ant && view[2].color != TRAIL) return {cell: 2};
        else if (view[8].color == TRAIL && !view[0].ant && view[0].color != TRAIL) return {cell: 0};
        //Can't find color, or path is blocked? try diagonals regardless of color
        else if (!view[0].ant) return {cell: 0};
        else if (!view[2].ant) return {cell: 2};
        else if (!view[6].ant) return {cell: 6};
        else if (!view[8].ant) return {cell: 8};
        //Everything else failed? Stay put.
        else return {cell: 4};
    }
    //good
    if (view[4].color == TRAIL) { //If on colored square, try to move
        var totGreen = 0;
        for (var i = 0; i < 9; i++) { //Look for food
            if (view[i].food) {
                return {cell: i};
            }
            if(view[i].color == TRAIL) totGreen++;
        }
        var ret = getTrailMove();
        if(view[deRotate(ret.cell,1)].color == TRAIL && totGreen <= 4) ret.cell = deRotate(ret.cell,-1);
        else if(view[deRotate(ret.cell,-1)].color == TRAIL && totGreen <= 4) ret.cell = deRotate(ret.cell,1);
        return ret;
    } else { //If not on colored square, look for food, or set current color to 2.
        for (var i = 0; i < 9; i++) { //Look for enemies
            if (i != 4 && view[i].ant != null && !view[i].ant.friend) {
                var r = findOpenSpace(8-i,1);
                if(view[r].color == TRAIL) r = deRotate(r,1);
                return {cell: r};
            }
        }
        return {cell: 4, color:TRAIL};
    }
}

function getTrailMove() {
    if (view[0].color == TRAIL && !view[8].ant && view[8].color != TRAIL) return {cell: 8};
    else if (view[2].color == TRAIL && !view[6].ant && view[6].color != TRAIL) return {cell: 6};
    else if (view[6].color == TRAIL && !view[2].ant && view[2].color != TRAIL) return {cell: 2};
    else if (view[8].color == TRAIL && !view[0].ant && view[0].color != TRAIL) return {cell: 0};
    //Can't find color, or path is blocked? try diagonals regardless of color
    else if (!view[0].ant) return {cell: 0};
    else if (!view[2].ant) return {cell: 2};
    else if (!view[6].ant) return {cell: 6};
    else if (!view[8].ant) return {cell: 8};
    //Everything else failed? Stay put.
    else return {cell: 4};
}

function firebreak() {
    var ret = -1;
    if(findWorker(5) >= 0) {
        return {cell:8-findWorker(5)};
    }
    if(view[4].color != 5) {
        var myView = [0,0,0,0,0,0,0,0,0]
        for(var i=0; i < 9; i++) {
            myView[i] = view[i].color
            if(view[4].ant.food > 0 && view[i].food > 0) {
                myView[i] = 8;
            }
            if(view[i].ant != null && !view[i].ant.friend) return {cell:findOpenSpace(deRotate(i,2),1)};
        }
        var ret = clearAhead(myView);
        if(ret == null)
            return {cell:4,color:5};
        else {
            if(!(view[ret.cell].ant != null && view[ret.cell].ant.friend == false) && (view[4].ant.food == 0 || view[ret.cell].food == 0))
                return ret;
            return {cell:4,color:5};
        }
    }
    if(view[1].color == 5 && view[3].color == 5 && view[5].color == 5 && view[7].color == 5) {
        if(view[0].color != 8) return {cell:0,color:8};
        if(view[1].color != 8) return {cell:1,color:8};
    }
    if(view[1].color == 5 && view[7].color != 5) ret = {cell:7};
    if(view[3].color == 5 && view[5].color != 5) ret = {cell:5};
    if(view[5].color == 5 && view[3].color != 5) ret = {cell:3};
    if(view[7].color == 5 && view[1].color != 5) ret = {cell:1};
    if(view[1].color != 5 && view[3].color != 5 && view[5].color != 5 && view[7].color != 5) ret = {cell:1};
    if((view[1].color == 5 && view[7].color == 5) || (view[3].color == 5 && view[5].color == 5)) ret = {cell:0};
    var loop = 0;
    while(ret.cell >= 0 && ((view[ret.cell].food > 0 && view[4].ant.food > 0) || view[ret.cell].ant != null) && loop < 9) {
        loop++;
        ret.cell = (ret.cell + 2) % 9;
    }
    if(loop < 9 && ret.cell >= 0) return ret;
    return {cell:4};
}

//7,6,4,2,3
//O7,D2

function highwayRobbery() {
    var move = basicHighwayMove();
    if(move.cell >= 0 && view[move.cell].ant != null) {
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + (view[4].color%2==0?1:HIGHWAY_COLORS.length);
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                return {cell:i};
            }
        }
    }
    return move;
}

function basicHighwayMove() {
    var isQueen = view[4].ant.type == 5;
    if(isHighwayCenter()) {
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                if(view[i].ant == null)
                    return {cell:i};
                else {
                    return {cell:deRotate(i,1)};
                }
            }
        }
    }
    else {
        if(view[4].color == 7) {
            //move diagonal to yellow (2)
            for(var i=0;i<9;i++) {
                if(i != 4 && i % 2 == 0 && view[i].color == 2) {
                    return {cell:i};
                }
            }
        }
        else {
            //move orthogonal to blue (7)
            for(var i=0;i<9;i++) {
                if(i % 2 == 1 && view[i].color == 7) {
                    //try ortho yellow first
                    for(var j=0;j<9;j++) {
                        if(j % 2 == 1 && view[j].color == 2 && areAdjacent(i,j))
                            return {cell:j};
                    }
                    return {cell:i};
                }
            }
            //if orthogonal blue doens't exist...
            //...try diagonal to magenta
            for(var i=0;i<9;i++) {
                if(i != 4 && i % 2 == 0 && view[i].color == 3) {
                    return {cell:i};
                }
            }
            if(view[4].color != 2) {
                //...try diagonal blue
                for(var i=0;i<9;i++) {
                    if(i % 2 == 0 && view[i].color == 7)
                        return {cell:i};
                }
            }
            //...and orthogonal yellow
            for(var i=0;i<9;i++) {
                if(i % 2 == 1 && view[i].color == 2)
                    return {cell:i};
            }
        }
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                return {cell:i};
            }
        }
    }
    return {cell:-1};
}

function isOnHighway() {
    var match = 0;
    var nxt = HIGHWAY_COLORS[(HIGHWAY_COLORS.indexOf(view[4].color)+1) % HIGHWAY_COLORS.length];//4
    var prv = HIGHWAY_COLORS[(HIGHWAY_COLORS.indexOf(view[4].color)+HIGHWAY_COLORS.length-2) % HIGHWAY_COLORS.length];//6
    for(var i=0;i<9;i++) {
        if(HIGHWAY_COLORS.indexOf(view[i].color) >=0 && (i == 4 || view[i].color != view[4].color))
            match++;
    }
    if(match >= 5) {
        //7,6,4,2,3


        if((view[1].color == nxt && view[7].color == prv)||(view[1].color == prv && view[7].color == nxt) || 
            (view[3].color == nxt && view[5].color == prv)||(view[3].color == prv && view[5].color == nxt)) {
            return true;
        }
        if((view[1].color == view[8].color && (view[1].color == nxt || view[1].color == prv))||(view[1].color == view[6].color && (view[1].color == nxt || view[1].color == prv)) || 
            (view[3].color == view[2].color && (view[3].color == nxt || view[3].color == prv))||(view[3].color == view[8].color && (view[3].color == nxt || view[3].color == prv))) {
            return true;
        }
        if((view[0].color == view[7].color && (view[0].color == nxt || view[0].color == prv))||(view[2].color == view[7].color && (view[2].color == nxt || view[2].color == prv)) || 
            (view[0].color == view[5].color && (view[0].color == nxt || view[0].color == prv))||(view[6].color == view[5].color && (view[6].color == nxt || view[6].color == prv))) {
            return true;
        }
        if(isHighwayCenter()) {
            return true;
        }
    }
    return false;
}

function isHighwayCenter() {
    if(HIGHWAY_COLORS.indexOf(view[4].color) >=0 && (((view[0].color != view[8].color || view[2].color != view[6].color) && view[4].ant.type == 1) || (view[0].color != view[8].color && view[2].color != view[6].color))){
        var m1 = view[1].color == view[7].color;
        var m2 = view[2].color == view[8].color;
        var m3 = view[0].color == view[6].color;
        var m4 = view[0].color != 1 && view[2].color != 1;
        if((m1?1:0)+(m2?1:0)+(m3?1:0) >= 2 && m4) {
            if(view[3].color != view[5].color && ((view[2].color != view[5].color && view[8].color != view[5].color) || view[4].ant.type == 1) && ((view[3].color != view[0].color && view[3].color != view[6].color) || view[4].ant.type == 1)) {
                return true;
            }
        }
        m1 = view[3].color == view[5].color;
        m2 = view[0].color == view[2].color;
        m3 = view[6].color == view[8].color;
        m4 = view[0].color != 1 && view[6].color != 1;
    //good
        if((m1?1:0)+(m2?1:0)+(m3?1:0) >= 2 && m4) {
            m1 = view[1].color != view[7].color;
            m2 = (view[0].color != view[1].color && view[1].color != view[2].color);
            m3 = (view[6].color != view[7].color && view[7].color != view[8].color);
            if(m1 && m2 && m3) {
                return true;
            }
            if(view[4].ant.type == 1 && ((m1?1:0)+(m2?1:0)+(m3?1:0)) >= 2) {
                return true;
            }
        }
    }
    return false;
}

function deRotateSide(m, amt) {
    return deRotate(m,amt*2);
}

/**Positive amount is clockwise**/
function deRotate(m, amt) {
    var rotationsCW = [1,2,5,8,7,6,3,0];
    var rotationsCCW = [3,6,7,8,5,2,1,0];
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m;
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8];
    amt = -amt;
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8];
}

function areAdjacent(A, B) {
    if(A == 4 || B == 4 || A == B) return true;
    if(A % 2 == 0 && B % 2 == 0) return false;
    if(A % 2 == 1 && B % 2 == 0) return areAdjacent(B,A);
    if(A % 2 == 1 && B % 2 == 1) return !(8-A == B || 8-B == A);
    if(A == 0 && (B == 1 || B == 3)) return true;
    if(A == 2 && (B == 1 || B == 5)) return true;
    if(A == 6 && (B == 3 || B == 7)) return true;
    if(A == 8 && (B == 5 || B == 7)) return true;
    return false;
}

function findFirstTrail() {
    var pos = 0;
    var b = 0;
    while(view[pos].color != TRAIL && b < 8) {
        pos=deRotate(pos,1);
        b++;
    }
    return pos;
}

function clearAhead(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(view[i].color == 5) c++;
        if(view[i].color == 5 && i%2 == 0) c+=10;
    }
    if(c == 2) {
        if(view[0].color == 5 || view[2].color == 5 || view[6].color == 5 || view[8].color == 5) {
            return {cell:4,color:5};
        }
        if(view[0].ant == null)
            return {cell:0};
        if(view[2].ant == null)
            return {cell:2};
        if(view[6].ant == null)
            return {cell:6};
        if(view[8].ant == null)
            return {cell:8};
    }
    c = 0;
    sides[4] = 0;
    var toMatch =[{state:[1,1,1,
                          2,0,2,
                          0,1,0]},
                 {state:[0,2,1,
                         1,0,1,
                         0,2,1]},
                 {state:[0,1,0,
                         2,0,2,
                         1,1,1]},
                 {state:[1,2,0,
                         1,0,1,
                         1,2,0]}];
    for(var m=0;m<4;m++) {
        var score=0;
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(sides[j] == 5 && toMatch[m].state[j] == 1) {
                    score++;
                }
                if(sides[j] != 5 && (toMatch[m].state[j] == 0 || toMatch[m].state[j] == 2)) {
                    score++;
                }
                if(sides[j] == 5 && toMatch[m].state[j] == 2) {
                    score--;
                }
            }
        }
        if(score >= 6) {
            var clearOrder=[1,0,2];
            for(var r=0;r<clearOrder.length;r++) {
                var s = deRotateSide(clearOrder[r],m);
                if(view[s].color == 5) {
                    if(view[s].ant == null)
                        return {cell:s,color:8};
                    else
                        return {cell:4};
                }
            }
        }
    }
    return null;
}

function findOpenSpace(pos, dir) {
    if(pos > 8 || pos < 0) return pos;
    var b = 0;
    while(view[pos].ant != null && b < 8) {
        pos=deRotate(pos,dir);
        b++;
    }
    return pos;
}

function getHighestWorker() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type > r) r = view[i].ant.type;
        }
    }
    return r;
}

function getNumWorkers(type) {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type == type) r++;
        }
    }
    return r;
}

function findWorker(type) {
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type == type) return i;
        }
    }
    return -1;
}

422 %
업데이트가 4/22에 있었기 때문에 422 % 완료이 농담이 너무 오래 지속되었습니다

잘못된 움직임 감지 : 확인
켜기 : 확인
그들은 손질받을 때 Respawning 근로자 : 대부분 확인
음식을 피를 빨고 다른 개미에 붙어 피 ...

8/1 업데이트

자주 두 번 돌리면 ~ 15 % 더 많은 음식 수집

업데이트 8/2

견고성 대 달라 붙는 기능이 추가되었습니다.

9/9 업데이트

팔이 없으면 작업자 2와 3을 다시 생성하는 코드가 추가되었습니다.

9/12 업데이트

이전 업데이트를 되돌립니다. 글라이더는 새로 생성 된 팔로 앞으로 나아갈 수 있지만, 작업자는 회전하려고 할 때 순서가 잘못되어 날아갑니다.

이 문제를 해결하는 것 외에도 respawn-all-workers 코드를 좀 더 차별적으로 재구성했습니다. 근처의 "잃어버린"작업자와의 충돌을 줄이고 60 개 이상의 음식을 완전히 리스폰하는 것을 방지합니다. 대부분 짧은 시간 안에 다시 벗겨 질 가능성이있는 근로자에게 음식 4 개를 소비하는 것보다 낫습니다. 어쨌든 글라이더의 능력을 능가하는 경우를 제외하고는 60 명 이상의 개미가 거의 없습니다. 또한 잃어버린 노동자들이 다른 개미 산책로를 엉망으로 만들 수 있도록 코드를 추가했습니다.

글라이더가 움직일 수있을 때에도 글라이더가 멈출 수있는 상황과 관련된 다른 픽스는 거의 없습니다 (예 : 여왕이 팔을 움켜 잡고 나중에 리스폰하도록하는 것).

정의 된 변수를 사용하도록 색상을 재구성하고 레일의 레일 시스템에서 광부에서 "트랩"되는 것을 피하기 위해 트레일 색상을 노란색에서 녹색으로 변경했습니다 (솔로 퀸은 지속적으로 리디렉션 됨).

새로운 코드 중 일부는 다른 항목 인 Black Hole 에서 통합되었습니다 .

9/13 업데이트

스폰 된 오리엔테이션 코드의 버그가 수정되었습니다. 2s 핸들 이 s (으)로 변환되었습니다 TRAIL.

1/21 업데이트

  • 글라이더는 이제 왼쪽으로 움직일 수 있습니다 (애니메이션 보류 중).
  • 음식이 준비 되 자마자 한 명의 노동자를 낳음으로써 초기 게임이 가속화되었습니다.
  • 원 암 글라이딩도 양방향으로 회전 할 수 있습니다.
  • "직원을 리스폰하지 마십시오"임계 값이 상승했습니다.
  • "다시 버리거나 실패하려는 음식을 낭비하지 마십시오"가 %5에서%3

1/25 업데이트

  • 일부 교착 상태 시나리오를 수정하여 일부 경기에서 효율성을 약간 향상 시켰습니다.

2/20 업데이트

  • 5 가지 및 3 가지 구성을보다 안정적으로 만드는 여러 가지 대폭 폭발 / 교착 상태 시나리오를 해결했습니다. 여러 가지 음식 배치로 인해 글라이더가 혼란스러워지고 교착 상태 (반복적으로 앞뒤로 회전)가 발생하거나 폭발 할 수 있습니다.
    • 한 번의 폭발은 스위퍼 개미가 회전의 마지막 단계에서 음식으로 이동 한 후 "똥, 나는 음식이 있고, 여왕에게 가져 가기 위해 희생한다"고 가정 할 때 (표준 이동은 유효했습니다) ).
    • 하나의 폭발은 이미 여왕의 세포가 TRAIL녹색 (녹색) 인 결과로, 여왕의 "정지 상태"움직임 중 하나를 유발했습니다 (여왕 foreverAlone()이 그룹에서 멀어 지도록 폴백을 처리 함) . 여왕이 행동하기 직전에 여왕의 세포의 색깔.
    • 여왕의 코드를 고치는 것보다 더 바람직하다. 왜냐하면 foreverAlone()우리가 날개를 구할 수없는 경우에도 폴백을 유지 하고 여왕을 꺼내서 발생할 수있는 교착 상태를 피할 수 있기 때문이다.
  • foreverAlone()여왕 아래의 세포가 TRAIL(녹색) 경우에만 음식으로 이동하도록 기능이 업데이트되었습니다 . 매우 작은 효율 손실.
  • 글라이더 재 구축은 인접 그린 셀, 변경 findFirstYellow()및 사용법을 찾습니다 . 이것은 이전 탄환과 결합하여 이전에 본 세포 및 / 또는 최근 폭발 현장을 피하는 것이 더 좋습니다. 사선.
    • 기능 이름 변경 : 노란색은 오랫동안 오랫동안 여왕의 트레일 색상이 아닙니다.
    • 함수는 하였다 잘못 인해 부정형 논리 확인하는 "흔적의 첫번째 셀을"위치 : while ==대신while !=

2/25 업데이트

  • 더 많은 엣지 케이스 폭발 / 충돌 / 교착 상태 수정으로 전반적인 성능 향상
  • Alion이 제안한 LightSpeed와 유사한 동작의 일부 변경 ( 자체 항목의 동작에서 ). 일반적으로 음식 수집이 증가하지만 특정 교착 상태 시나리오는 피합니다.

업데이트 3/11 : 고속도로 스위치 동작에서 뱀파이어와 같은 "훔치는 음식"시스템으로 보이는 부서진 글라이더 날개. 대부분의 여왕이 자신 이 고속도로 안에 혼자 있지 않는 한 큰 의미는 없을 것 입니다.

1 번 작업자는 고속도로 중앙 회랑에서 수리를 시도하고, 허위 센터가 아닌 고속도로 지점에서 허위 센터를 발견 한 경우에는 추방 중단을 시도합니다. 여왕과 같은 방향으로 이동합니다 (직원 2, 3, 4에 대응).

노동자 2, 3, 4는 고속도로 여왕에 대한 드라이브 바이 도난을 시도한 다음 자신의 여왕에게 돌아갑니다.

  • 자신의 일꾼을 볼 수 없다
  • 마젠타에 앉아있다
  • 임계 값 사이에 음식이 있습니다 (양쪽에 부드러운 경계가 있음)
  • 간단한 무작위로 수정

이렇게하면 너무 많은 근로자가 생성되는 것을 피할 수 있으며 (~ 100까지 일할 수 있음) 많은 노동 근로자가 돌아올 때 (자체 근로자를 볼 때 발생하지 않기 때문에) 순 식량 수입이 결국 글라이더를 최고 임계 값 이상으로 끌어 올리고 감소) 신규 근로자.

이것은 뱀파이어에 글을 쓸 계획 이었지만 Vampire가 Highway 퀸을 막고 그녀의 마른 일을 피하려고 시도한 첫 번째 시도 였으므로이 행동을 만드는 동기는 없었습니다. 고속 탐지 코드는 처음부터 작성되었으며 뱀파이어와는 다르지만 패턴의 단순성 때문에 미러 탐지 (IsHighwayCenter)는 매우 유사합니다.

3/16 업데이트

두 가지 사소한 버그 수정 (편집 기록 참조) 외에도 역 추적을 피하기 위해 Forever Alone 기능 (원래 도난 ...?)을 최적화하여 여왕이 평균적으로 더 많은 셀을 관찰 할 수있게했습니다.

highwayRobbery()개미가 고속도로 중심에있을 때 함수가 유효한 이동을 반환하지 못했을 때 폴백 이동 방법이 추가되었습니다 (그리고 다른 논리로는 이것을 합리적인 값으로 조정하지 않았습니다). 경우 실패, 개미는 표준 글라이딩 로직을 수행합니다.

약간의 조정

  • 여왕은 더 이상 고속도로에 있다는 것을 감지했을 때 산란을 시작하지 않습니다.
  • 여왕은 더 이상 칼로리를 소모하여 절대로 완료되지 않는 글라이더 형성을 완료하려고 시도하지 않습니다 (작업자 4를 생성합니다.
  • 고속도로 색상주기와 동일하게 식품 모듈러스 값을 조정했습니다.
  • 교착 상태를 유발하는 "1 개의 팔로 마무리"가 수정되었습니다.
  • isOnHighway()수표 에 대한 사소한 수정
  • 고속도로에있을 때 개미가 직교 파란색 셀로 이동하기 전에 개미가 직교 노란색으로 이동하게합니다 (분리 된 후 중심점을 찾는 1 번 저장).

3/26 업데이트

더 작은 조정.

4/21 업데이트

사소한 수정.


Steamroller를 기반으로 합니다.

노란색 흔적 뒤에 남은 음식 4 개를 수집합니다. 음식이 네 개가되면, 그 주위에 각 노동자 유형 중 하나를 생산합니다. 그런 다음 최대 추력에서 미끄러지기 시작합니다. 맨 위로 애니메이션을 이동하려면 1 번 게임을 완료해야합니다. 작업자 1이 먼저 생성되면 여왕과 차례를 마치기 전에 먼저 1, 2, 3, 4를 실행합니다. 선회 애니메이션은 2 턴이 걸리며, 짧은 일시 정지는 여왕이 수행 {cell:4}할 때, 작업자 3, 4 및 여왕이 모두 {cell:4}계속 활공을 준비하기 위해 수행 할 때 음식이 움직 입니다.


나는이 로봇 아이디어를 좋아합니다
Destructible Lemon

1
@DestructibleLemon 감사합니다! 나는 Steamroller / Piercer에 대해 생각하고 있었고, "여보, 여왕은 마지막에 간다, 확실히 나는 5 마리의 개미가 멋지게 놀 수있다"고 생각했다. 한 장의 종이를 잡고, 사각형을 찢어 움직이기 시작했다. 그것은 약간의 코드를 작성하여 작동했습니다. 엣지 케이스에 대해 많은 오류 처리 및 버그 수정을 수행해야했습니다 (초기 봇은 막힐 수 있거나 수행 할 수있는 모든 음식을 소비 할 것입니다. 턴 작업을 추가하면 형성 및 충돌을 일으킬 수있는 엣지 케이스 시나리오가 많이 도입되었습니다 ).
Draco18s

다른 개미와 충돌 할 때까지 @trichoplax?
파괴 가능한 레몬

@DestructibleLemon eeeehhhh ... 아마도. 그것은 실격 되지 않습니다 ...
Draco18s

3
@KZhang 아 내가했다. 코멘트를 찾으십시오 "// 시도 회전"
Draco18s

13

풍차 비슷한 것

다음은 풍차입니다. 라만차 (La Mancha)의 뱀파이어 (La Mancha의 뱀파이어?)

풍차, 게임의 초기 중간 단계

나는 그 대답의 편집 기록으로 강등 된 Rails on Rails 의 디자인이 얼마나 더 멀리 나아갈 수 있는지 탐구하려고 노력했으며 , 디딤돌 이 광산 샤프트의 다른 벽에 더 잘 칠해져 있다는 관찰에 의해 촉진되었습니다 . 그리고 나서 그것은 단지 성장하고 진화했습니다 ...

우리의 헤비급 레일과 경량 샤프트 지오메트리는 거의 동일하고 레일 패턴이 비슷해 일부 개미가 다른 개미를 실수로 잘못 인식 할 수 있지만 구현은 처음부터 코딩 스타일로 훨씬 더 보행자에게 쓰여지고 새로운 키 하나를 도입합니다. 생각. 허브를 확대하여 밀링 을 봅니다 .

var AJM=1;var ASM=2;var AE=3;var ASF=4;var AQ=5;var RW=true;var EFCO=false;var THC=1;var TH0=0;var TH1=15;var TH2=17;var TH3=67;var TH4=120;var TH5=390;var THX=15;var THFCO1=9;var THFCO2=26;var THFCO3=75;var RM1=7;var RD1=4;var RM2=19;var RD2=THX;var PW=1;var PY=2;var PP=3;var PC=4;var PR=5;var PG=6;var PB=7;var PK=8;var LN=0;var LCLR=PW;var LT=PB;var LLSF=PP;var LA=PP;var LRL0=PC;var LRL1=PG;var LRL2=LRL0;var LRM0=PR;var LRM1=PB;var LRM1_WRP=PK;var LRM2=PG;var LRR0=PG;var LRR1=PW;var LRR1U=PR;var LRR1V=PY;var LRR1X=PK;var LRR2=PY;var LMX_M0=LCLR;var LMX_M1IN=PC;var LMX_M1OUT=PY;var LMX_M2IN=PP;var LMX_M2OUT=PR;var LMX_M3IN=PB;var LMX_M3OUT=PK;var LMS_WRP=PK;var LMR0=PK;var LML1=PY;var LMR2=PR;var LML3=PC;var LMMF=PG;var LMMH=PP;var LG3=PK;var LG4=PR;var LG5=PK;var LG6=PB;var LP0=LCLR;var LPB=PC;var LPG=PY;var LPG1=PR;var LPX=PP;var FALSE_X9=[false,false,false,false,false,false,false,false,false];
var UNDEF_X9=[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
var QCPERD=6;var LCL_QC_RESET=LCLR;var LCRQC=[PY,PP,PC,PR,PG,PK];var LCRQCVAL=Array.from(FALSE_X9);var LCRQC_VALUE=Array.from(UNDEF_X9);for (var i=0; i<QCPERD; i++){LCRQCVAL[LCRQC[i]]=true;LCRQC_VALUE[LCRQC[i]]=i;}var SCPERD=7;var LCL_SC_RESET=LCLR;var LCRSC=[PY,PP,PC,PR,PG,PB,PK];var LCRSCVAL=Array.from(FALSE_X9);var LCRSC_VALUE=Array.from(UNDEF_X9);for (i=0; i<SCPERD; i++){LCRSCVAL[LCRSC[i]]=true;LCRSC_VALUE[LCRSC[i]]=i;}var LCRPHR=Array.from(FALSE_X9);LCRPHR[LPG]=true;LCRPHR[LPG1]=true;var LCRPHASES=Array.from(LCRPHR);LCRPHASES[LPX]=true;var LCRGRM1=Array.from(FALSE_X9);LCRGRM1[LRM1]=true;LCRGRM1[LRM1_WRP]=true;var LCRGRM_ALL=Array.from(FALSE_X9);LCRGRM_ALL[LRM0]=true;LCRGRM_ALL[LRM1]=true;LCRGRM_ALL[LRM1_WRP]=true;LCRGRM_ALL[LRM2]=true;var LCRGRR1_OUT=Array.from(FALSE_X9);LCRGRR1_OUT[LRR1V]=true;LCRGRR1_OUT[LRR1X]=true;var LCRGRR1B=Array.from(LCRGRR1_OUT);LCRGRR1B[LRR1U]=true;var LCRGRR1=Array.from(LCRGRR1B);LCRGRR1[LRR1]=true;var LCRMX_IO=Array.from(FALSE_X9);LCRMX_IO[LMX_M1IN]=true;LCRMX_IO[LMX_M1OUT]=true;LCRMX_IO[LMX_M2IN]=true;LCRMX_IO[LMX_M2OUT]=true;LCRMX_IO[LMX_M3IN ]=true;LCRMX_IO[LMX_M3OUT]=true;var LCRMX=Array.from(LCRMX_IO);LCRMX[LMX_M0]=true;var LCRMX_IN=Array.from(FALSE_X9);LCRMX_IN[LMX_M1IN]=true;LCRMX_IN[LMX_M2IN]=true;LCRMX_IN[LMX_M3IN ]=true;var LCRMX_OUT=Array.from(FALSE_X9);LCRMX_OUT[LMX_M1OUT]=true;LCRMX_OUT[LMX_M2OUT]=true;var LCRMM_FOOD=Array.from(FALSE_X9);LCRMM_FOOD[LCLR]=true;LCRMM_FOOD[LMMF]=true;var LCRMM_HOME=Array.from(FALSE_X9);LCRMM_HOME[LCLR]=true;LCRMM_HOME[LMMH]=true;var LCRMS=Array.from(FALSE_X9);LCRMS[LCLR]=true;LCRMS[LMS_WRP]=true;var LCRFRLL0=Array.from(FALSE_X9);LCRFRLL0[LCLR]=true;LCRFRLL0[LMR0]=true;LCRFRLL0[LMR2]=true;LCRFRLL0[LRM0]=true;LCRFRLL0[LRM2]=true;var LCRFRLL1=Array.from(FALSE_X9);LCRFRLL1[LCLR]=true;LCRFRLL1[LMR0]=true;LCRFRLL1[LMR2]=true;LCRFRLL1[LRR0]=true;LCRFRLL1[LRM1]=true;LCRFRLL1[LRR2]=true;var LCRFRLL2=Array.from(FALSE_X9);LCRFRLL2[LCLR]=true;LCRFRLL2[LMR0]=true;LCRFRLL2[LMR2]=true;LCRFRLL2[LRM0]=true;LCRFRLL2[LRR1V]=true;var TN=8;var POSC=4;var NOP={cell:POSC};var AIMU=1;var AIML=3;var AIMR=5;var AIMD=7;var FWD_CELLS=[[ true,true,false,true,true,false,false,false,false ],[ true,true,true,true,true,true,false,false,false ],[ false,true,true,false,true,true,false,false,false ],[ true,true,false,true,true,false,true,true,false ],[ true,true,true,true,true,true,true,true,true ],[ false,true,true,false,true,true,false,true,true ],[ false,false,false,true,true,false,true,true,false ],[ false,false,false,true,true,true,true,true,true ],[ false,false,false,false,true,true,false,true,true ]];var PTNOM=-9;var PTHOME=[LRM0,LRL0,LRM0,LRL0,LN,LRL0,LN,LN,LRM0];var PTGARDEN=[LG6,LG5,LG4,LN,LN,LG3,LN,LRL0,LRL1];var PTFRM0=[LRL1,LRM1,LCRGRR1,LRL0,LRM0,LRR0,LRL2,LRM2,LRR2];var PTFRM1=[LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1,LRL0,LRM0,LRR0];var PTFRM2=[LRL0,LRM0,LRR0,LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1];var PTGRM0=[LRL1,LCRGRM1,LCRGRR1,LRL0,LRM0,LRR0,LRL2,LRM2,LRR2];var PTGRM1=PTFRM1;var PTGRM2=PTFRM2;var PTGRM2B=[LRL0,LRM0,LRR0,LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1B];var PTGRM1_WRP=[LRL2,LRM2,LRR2,LRL1,LRM1_WRP,LRR1X,LRL0,LRM0,LRR0];var PTFRL0=[LCRFRLL1,LRL1,LRM1,LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2];var PTFRL1=[LCRFRLL2,LRL2,LRM2,LCRFRLL1,LRL1,LCRGRM1,LCRFRLL0,LRL0,LRM0];var PTFRL0H=[LN,LRL1,LRM1,LN,LRL0,LRM0,LN,LN,LN];var PTFRL1G=[LCRFRLL2,LRL2,LRM2,LG3,LRL1,LCRGRM1,LCRPHASES,LRL0,LRM0];var PTFRL2=[LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2,LCRFRLL1,LRL1,LCRGRM1];var PTGRL0=[LCRFRLL1,LRL1,LCRGRM1,LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2];var PTGRL1=PTFRL1;var PTGRL2=PTFRL2;var PTGRR0=[LCRGRM1,LCRGRR1,LCLR,LRM0,LRR0,LMR0,LRM2,LRR2,LCRMX];var PTGRR2=[LRM0,LRR0,LMR0,LRM2,LRR2,LCRMX,LCRGRM1,LCRGRR1,LCLR];var PTGRR1=[LRM0,LCRGRM1,LRM2,LRR0,LCRGRR1,LRR2,LMR0,LCLR,LCRMX];var PTMS0R_IN=[LRR0,LRR1U,LRR2,LMR0,LCLR,LCRMX_IN,LCLR,LCLR,LML1];var PTMS0R_OUT=[LRR0,LRR1U,LRR2,LMR0,LCLR,LCRMX_IO,LCLR,LCLR,LML1];var PTMS0R_OUT1=[LRR0,LCRGRR1_OUT,LRR2,LMR0,LCLR,LCRMX,LCLR,LCLR,LML1];var PTMS0=[LCLR,LCRMM_HOME,LML3,LMR0,LCRMM_FOOD,LCLR,LCLR,LCLR,LML1];var PTMS1=[LMR0,LCRMM_HOME,LCLR,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS2=[LCLR,LCRMM_HOME,LML1,LMR2,LCRMM_FOOD,LCLR,LCLR,LCLR,LML3];var PTMS3=[LMR2,LCRMM_HOME,LCLR,LCLR,LCRMM_FOOD,LML3,LMR0,LCLR,LCLR];var PTMS1_IN=[LMR0,LCRMM_HOME,LCRMX_IN,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS1_IO=[LMR0,LCRMM_HOME,LCRMX_IO,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS0_OUT=[LCLR,LCLR,LML3,LMR0,LCLR,LCRMX_IO,LCLR,LCLR,LML1];var PTMS0_WRAPPING=[LCLR,LCRMM_HOME,LML3,LMR0,LCRMM_FOOD,LCRMS,LRL0,LRL1,LRL2];var PTGRL1_WRP=[LMR0,LCLR,LMS_WRP,LRL0,LRL1,LRL2,LRM0,LRM1_WRP,LRM2];var PTMS0FL=[LMMH,LML3,LN,LMMF,LCLR,LN,LCLR,LML1,LN];var PTMS1FL=[LMMH,LCLR,LN,LMMF,LML1,LN,LCLR,LCLR,LN];var PTMS2FL=[LMMH,LML1,LN,LMMF,LCLR,LN,LCLR,LML3,LN];var PTMS3FL=[LMMH,LCLR,LN,LMMF,LML3,LN,LCLR,LCLR,LN];var PTMS0FR=[LN,LCLR,LMMH,LN,LMR0,LMMF,LN,LCLR,LCLR];var PTMS1FR=[LN,LMR0,LMMH,LN,LCLR,LMMF,LN,LMR2,LCLR];var PTMS2FR=[LN,LCLR,LMMH,LN,LMR2,LMMF,LN,LCLR,LCLR];var PTMS3FR=[LN,LMR2,LMMH,LN,LCLR,LMMF,LN,LMR0,LCLR];var CCW=[6,7,8,5,2,1,0,3,6,7,8,5,2,1,0,3,6,7,8,5,2,1];
var xn=-1;var fwdWrong=[];var rearWrong=[];var here=view[POSC];var mC=here.color;var myself=here.ant;var mT=myself.type;var mF=myself.food;var mS=(mT==AE||(mT!=AQ&&mF>0));if (EFCO&&(mT==AQ)){if (mF<=THFCO1){QCPERD=5;} else if (mF<=THFCO2){QCPERD=4;} else if (mF<=THFCO3){QCPERD=5;}}var dOK=[true,true,true,true,true,true,true,true,true];
var uo=true;var sL=[0,0,0,0,0,0,0,0,0];var sD=[0,0,0,0,0,0,0,0,0];var sN=[0,0,0,0,0,0,0,0,0];var sT=[0,0,0,0,0,0,0,0,0];var fdL=0;var fdD=0;var fdT=0;sT[mC]++;for (i=0; i<TN; i+=2){var cell=view[CCW[i]];sD[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdD++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}for (i=1; i<TN; i+=2){var cell=view[CCW[i]];sL[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdL++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}var aF=[0,0,0,0,0,0];var aLF=[0,0,0,0,0,0];var aUF=[0,0,0,0,0,0];var fT=0;var mQ=0;var aE=[0,0,0,0,0,0];var aLE=[0,0,0,0,0,0];var aUE=[0,0,0,0,0,0];var eT=0;for (i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant){if (cell.ant.friend){aF[cell.ant.type]++;fT++;if (cell.ant.type==AQ){xn=i&6;mQ=i&1;}if (cell.ant.food>0){aLF[cell.ant.type]++;} else {aUF[cell.ant.type]++;}} else {aE[cell.ant.type]++;eT++;if (cell.ant.food>0){aLE[cell.ant.type]++;} else {aUE[cell.ant.type]++;}}dOK[CCW[i]]=false;uo=false;}}switch (mT){case AQ:return (rQSs());case ASF:if (mQ==1){return (rSSs());} else if (aF[AQ]>0){return (rGSs());} else {return (rLSSy());}case AE:return (rESs());case AJM:case ASM:if (aE[AQ]>0){return (rDSs());} else if (mF>0){return (rLSs());} else {return (rUSs());}default:return NOP;}function rQSs (){switch (aF[ASF]){case 0:return (rQScrSy());case 1:for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.type==ASF){xn=i&6;if (i&1){if (mF<=THX){return (rQLsSy());} else {return (rQLvSy());}} else {return (rQSgSy());}}}break;case 2:for (i=0; i<TN; i+=2){var cell0=view[CCW[i]];var cell1=view[CCW[i+1]];if ((cell0.ant&&(cell0.ant.type==ASF))&&(cell1.ant&&(cell1.ant.type==ASF))){xn=i;return (rQOSy());}}return (rQCSy());default:return (rQCSy());}return NOP;}function rSSs (){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&(view[CCW[xn+3]].ant.type==ASF)){return (rSOSy());} else if (view[CCW[xn+1]].ant.food<=THX){return (rSLSy());} else {return (rSESy());}}function rGSs (){var secCell=view[CCW[xn+7]];if (secCell.ant&&(secCell.ant.friend==1)&&(secCell.ant.type==ASF)){return (rGOSy());} else {return (rGSSy());}return NOP;}function rESs (){if (aF[AQ]>0){return (rEHyS());} else if (aF[AJM] +aF[ASM]>0){return (rEBRSy());} else {return (rEASy());}return NOP;}function rDSs(){if (aF[AQ]>0){return (rDHSy());} else {for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&(view[CCW[i]].ant.type==AQ)){if (i&1){if ((view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&view[CCW[i+2]].ant&&view[CCW[i+2]].ant.friend)||(view[CCW[i-1]].ant&&view[CCW[i-1]].ant.friend&&view[CCW[i+6]].ant&&view[CCW[i+6]].ant.friend)||(view[CCW[i+2]].ant&&view[CCW[i+2]].ant.friend&&view[CCW[i+6]].ant&&view[CCW[i+6]].ant.friend)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};}}} else {if (view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
view[CCW[i+7]].ant&&view[CCW[i+7]].ant.friend){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if (dOK[CCW[i+6]]){return {cell:CCW[i+6]};} else if (dOK[CCW[i+2]]){return {cell:CCW[i+2]};}}if ((i<=2)&&dOK[CCW[i+7]]){return {cell:CCW[i+7]};}if ((i>=4)&&dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}if (fT==0){if (view[CCW[i]].color!=PP){return {cell:CCW[i],color:PP};} else if (mC!=LCLR){return {cell:POSC,color:LCLR};}}}}}return NOP;}function rUSs (){if ((aF[AQ]>0)&&!LCRQCVAL[view[CCW[xn+mQ]].color]){return (rUHSy());} else if ((fT+eT>=4)&&(aF[AJM]+aF[ASM] +aF[AE]>=3)){return (rUCRSy());} else if (aF[AQ]>0){return (rUHSy());} else if (aF[ASF]>0){if (aF[ASF]>1){return (rM2R1Sy());} else {return (rURHSy());}} else if (aF[AE]>0){return (rUBRSy());} else if (spcRL1()){return (rULRL1Sy());} else if (spcRR0()){return (rULRR0Sy());} else if (spcRR2()){return (rULRR2Sy());} else if (spcMS()){return (rUDSSy());} else if (spcRL02()){return (rULRL02Sy());} else if (spcRM()){return (rUTRRSy());} else if (spcRR1()){return (rUPSSy());} else if (spcMS0R()){return (rUESSy());} else if (spcMS0W()){return (rUSWSy());}return (rLostMSy(true));}function rLSs (){if ((fT>=3)&&(fT+eT>=4)){return (rLCRSy());} else if (aF[ASF]>0){if (aF[ASF]>1){return (rM2R1Sy());} else {return (rLRHSy());}} else if (spcMFL()){return (rLLLWSy());} else if (spcMFR()){return (rLLRWSy());} else if (spcRL1()){return (rLLRL1Sy());} else if (spcRR0()){return (rLLRR0Sy());} else if (spcRR2()){return (rLLRR2Sy());} else if (spcMS0R()){return (rLLSSy());} else if (spcMS0ROut()){return (rLLVSSy());} else if (spcMS()&&(aF[AE]==0)){return (rLASSy());} else if (spcRL02()){return (rLLRL02Sy());} else if (spcRM()){return (rLTRRSy());} else if (spcRR1()){return (rLDSSy());} else if (aF[AE]>0){return (rLFRSy());}return (rLostMSy(true));}function rQScrSy(){if (uo){if (fdT>0){return (rQSETc());} else if (mF>=THC){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+1],type:ASF};}}return {cell:1,type:ASF};} else if (mC!=LT){if ((mC==LCLR)||(sN[LCLR]>=TN-1)){return {cell:POSC,color:LT};} else {return (rQSTCTc());}} else if ((sN[LCLR]>=4)&&(sN[LT]==1)){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+4]};}}} else if (sN[LCLR]==TN){return {cell:0};} else {return (rQSATc());}} else {if ((fdT>0)&&(eT>0)&&(eT==aE[AQ])){return (rQSSTc());} else {return (rQSEvTc());}}return NOP;}function rQSgSy(){if (fdT>0){if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {for (var i=2; i<TN-1; i++){if (dOK[CCW[xn+i]]&&(view[CCW[xn+i]].food>0)){return {cell:CCW[xn+i]};}}for (var i=2; i<TN-1; i++){if (dOK[CCW[xn+i]]){     return {cell:CCW[xn+i]};}}return NOP;}} else if ((mF>TH0)&&(mC==LCL_QC_RESET)){if (dOK[CCW[xn+7]]){return { cell:CCW[xn+7],type:AE};} else if (view[CCW[xn]].color==LPB){if (dOK[CCW[xn+3]]){return { cell:CCW[xn+3],type:AE};} else if (dOK[CCW[xn+5]]){return { cell:CCW[xn+5],type:AE};} else if (dOK[CCW[xn+6]]){return { cell:CCW[xn+6],type:AJM};} else if (dOK[CCW[xn+2]]){return { cell:CCW[xn+2],type:AJM};} else if (dOK[CCW[xn+4]]){return { cell:CCW[xn+4],type:AJM};} else if (dOK[CCW[xn+1]]){return { cell:CCW[xn+1],type:ASF};}}}return NOP;}function rQOSy(){if ((aE[AQ]>0)&&(mF>0)){for (var i=2; i<TN; i++){if (view[CCW[xn+i]].ant&&(view[CCW[xn+i]].ant.type==AQ)&&!view[CCW[xn+i]].ant.friend){var j=(xn&4) ? 1 : -1;if (dOK[CCW[xn+i-j]]){return {cell:CCW[xn+i-j],type:AJM};} else if (dOK[CCW[xn+i+j]]){return {cell:CCW[xn+i+j],type:AJM};} else if (i==5){var i1=5-2*j;var i2=5+2*j;if (dOK[CCW[xn+i1]]&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&
view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
view[CCW[xn+i2]].ant&&view[CCW[xn+i2]].ant.friend)){return {cell:CCW[xn+i1],type:AJM};} else if (dOK[CCW[xn+i2]]&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&
view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
view[CCW[xn+i1]].ant&&view[CCW[xn+i1]].ant.friend)){return {cell:CCW[xn+i2],type:AJM};}} else if ((i==3)&&dOK[CCW[xn+5]]&&!(view[CCW[xn+2]].ant&&view[CCW[xn+2]].ant.friend&&
view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend)){return {cell:CCW[xn+5],type:AJM};} else if ((i==7)&&dOK[CCW[xn+5]]&&!(view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend)){return {cell:CCW[xn+5],type:AJM};}}}} else if ((mF>0)&&(view[CCW[xn+7]].color==LA)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7],type:AJM};} else if (view[CCW[xn+1]].ant.food>0){if ((mF>0)&&dOK[CCW[xn+2]]){return {cell:CCW[xn+2],type:AJM};}} else if ((aLF[AJM]+aLF[ASM]>0)&&(mF>0)&&(sN[LA]>0)){for (var i=2; i<TN; i++){var c=CCW[xn+i];if (dOK[c]&&(view[c].color==LA)){return {cell:c,type:AJM};}}} else if (eT>0){var bandits=aUE[1]+aUE[2]+aUE[3]+aUE[4];if ((mF>THX)&&((bandits>=2)||((bandits>=1)&&view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].color==LA)&&(view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&
(view[CCW[xn+7]].color==LA))||(view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&
(view[CCW[xn+3]].color==LA))))){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}if (mF<RD1){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}} else if ((bandits>=1)&&(mF>0)){if ((mF>THX)&&(mF % RM2==RD2+xn/2)){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}for (var i=2; i<TN; i++){var c=CCW[xn+i];var c1,c2;if ((xn==2)||isSc0(view[CCW[xn+1]].color)){c1=CCW[xn+i-1];c2=CCW[xn+i+1];} else if ((xn==6)||isSc1(view[CCW[xn+1]].color)){c1=CCW[xn+i+1];c2=CCW[xn+i-1];} else {break;}if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.food==0)){if (dOK[c1]&&!(view[c2].ant&&view[c2].ant.friend&&view[c2].ant.food>0)){return {cell:c1,type:AJM};} else if (dOK[c2]&&!(view[c1].ant&&view[c1].ant.friend&&view[c1].ant.food>0)){return {cell:c2,type:AJM};}break;}}}}if (!(LCRQCVAL[mC])){return {cell:POSC,color:LCRQC[1]};} else if ((view[CCW[xn]].color==LPX)&&isSc0(view[CCW[xn+1]].color)){if ((mF<=TH0)||(mF % RM1==RD1)){return (rQHTc());} else if (mF<=TH2){if (dOK[CCW[0]]){return {cell:CCW[0],type:AJM};} else {return (rQHTc());}} else {var destCycle=[2,4,6,4,6,2,6,2,4];var destination=destCycle[mF % 9];if (!dOK[CCW[xn+destination]]){destination=destination % 6+2;}if (!dOK[CCW[xn+destination]]){destination=destination % 6+2;}if (!dOK[CCW[xn+destination]]){return (rQHTc());}if (mF<=TH3){if (xn<=2){return {cell:CCW[xn+destination],type:AJM};} else {return (rQHTc());}} else if (mF<=TH4){if (xn<=2){return {cell:CCW[xn+destination],type:((xn>0) ? AJM : ASM)};} else {return (rQHTc());}} else if (mF<=TH5){if (xn==0){return {cell:CCW[xn+destination],type:ASM};} else {return (rQHTc());}} else {return (rQHTc());}}} else {return {cell:POSC,color:incQc(mC)};}return NOP;}function rQLsSy(){if (mF>=TH1){if (mC!=LCLR){return {cell:POSC,color:LCLR};} else {for (var i=0; i<TN; i+=2){if (view[CCW[i]].color!=LCLR){return {cell:CCW[i],color:LCLR};}}}if ((eT==0)&&(fT==1)){return {cell:CCW[xn+3]};}}if ((eT==0)&&(fT==1)){if (view[CCW[xn+2]].food>0){return {cell:CCW[xn+2]};} else if ((view[CCW[xn+3]].food +view[CCW[xn+4]].food>0)&&(view[CCW[xn+1]].color!=LLSF)){return NOP;} else {return {cell:CCW[xn+2]};}} else if (dOK[CCW[xn+2]]&&(dOK[CCW[xn+3]]||(view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend))){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else {return NOP;}}function rQLvSy(){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}return NOP;}function rQCSy(){return NOP;}function rSOSy(){if (!(LCRSCVAL[mC])){return {cell:POSC,color:LCRSC[1]};} else if (isSc0(mC)&&isQc0(view[CCW[xn+1]].color)&&
(view[CCW[xn+3]].color==LPG)){return {cell:CCW[xn+3],color:LPX};} else {return {cell:POSC,color:incSc(mC)};}return NOP;}function rSLSy(){if ((eT==0)&&(fT==1)){if (view[CCW[xn]].food>0){return {cell:CCW[xn]};} else if (view[CCW[xn+7]].food +view[CCW[xn+6]].food>0){return {cell:POSC,color:LLSF};} else {return {cell:CCW[xn]};}} else if ((eT>0)&&view[CCW[xn+2]].ant&&!view[CCW[xn+2]].ant.friend){return {cell:POSC,color:LLSF};} else {if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}return NOP;}function rSESy(){if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].ant.type==ASF)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};}} else if ((mC==LRR0)&&(view[CCW[xn+5]].color==LG6)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};}} else {if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};}}return NOP;}function rGSSy(){if (view[CCW[xn]].color!=LCL_QC_RESET){return {cell:CCW[xn],color:LCL_QC_RESET};}if (mC!=LPB){return {cell:POSC,color:LPB};}return (rGGTc());}function rGOSy(){if (aE[AQ]>0){var c=CCW[xn+2];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}c=CCW[xn+3];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}}if (!LCRPHR[mC]){if ((mC==LPX)&&isSc0(view[CCW[xn+7]].color)){return NOP;} else if (eT==0){return {cell:POSC,color:LPG};}} else if (isSc1(view[CCW[xn+7]].color)&&isQc2(view[CCW[xn]].color)){switch (mC){case LPG:return {cell:POSC,color:LPG1};case LPG1:return {cell:POSC,color:LPG};default:return {cell:POSC,color:LPG};}}if ((eT>0)&&!LCRPHR[mC]&&(xn&4)){return {cell:POSC,color:LPG};} else {return (rGGTc());}}function rLSSy(){if (mC!=LCLR){return {cell:POSC,color:LCLR};}return NOP;}function rEHyS(){if (mQ==1){var ptrn=PTFRL0H;var msm=patC(ptrn,AIMU,0,1);if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (LCRQCVAL[view[CCW[xn+mQ]].color]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}}return NOP;}function rEBRSy(){if (aF[ASF]>0){return (rELGTc());} else {return (rEBRTc());}}function rEASy(){return NOP;}function rUHSy(){if ((mQ==0)&&(view[CCW[xn]].ant.food<RD1)&&view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&(view[CCW[xn+1]].ant.type==ASF)){var cc=[5,6,7,4,2];for (var i=0; i<cc.length; i++){var c=CCW[xn+cc[i]];if (dOK[c]){return {cell:c};}}return NOP;}if ((eT>0)&&(aE[AQ]+aUE[1]+aUE[2] +aUE[3]+aUE[4]>0)){var common;if (mQ==0){common=[1,7];} else {common=[0,2,3,7];}for (var i=0; i<common.length; i++){var c=CCW[xn+common[i]];if (view[c].ant&&!view[c].ant.friend&&((view[c].ant.type==AQ)||(view[c].ant.food==0))){if ((aE[AQ]==0)&&(mC!=LA)){return {cell:POSC,color:LA};} else {return NOP;}}}}if (mQ==0){if (mC!=LRM0){return {cell:POSC,color:LRM0};} else if (view[CCW[xn+3]].color!=LRR0){return {cell:CCW[xn+3],color:LRR0};} else if (view[CCW[xn+7]].color!=LRL0){return {cell:CCW[xn+7],color:LRL0};} else if (view[CCW[xn+5]].color!=LRM1){return {cell:CCW[xn+5],color:LRM1};} else if (view[CCW[xn+6]].color!=LRL1){return {cell:CCW[xn+6],color:LRL1};} else if ((!LCRGRR1[view[CCW[xn+4]].color])&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend)){return {cell:CCW[xn+4],color:LRR1};}if (LCRQCVAL[view[CCW[xn]].color]||(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
(view[CCW[xn+5]].ant.food>0))||(view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
(view[CCW[xn+6]].ant.food>0))){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};}}} else {var ptrn=PTFRL0H;var msm=patC(ptrn,AIMU,0,1);if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (LCRQCVAL[view[CCW[xn+mQ]].color]){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}}}return NOP;}function rUBRSy(){if (spcRL1()){return (rULRL1Sy());} else if (spcRL02()){return (rULRL02Sy());} else if (spcRM()){return (rUFCRTc());}for (var i=TN-1; i>=0; i--){if (view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
(view[CCW[i+1]].ant.type==AE)&&dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}function rUTRRSy(){return (rUCRTc());}function rULRL1Sy(){var ptrn=PTGRL1;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){if ((view[CCW[xn+6]].color==LMS_WRP)&&(view[CCW[xn+7]].color==LCLR)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+3]].color!=LRM1_WRP)){return {cell:CCW[xn+3],color:LRM1_WRP};} else if ((view[CCW[xn+3]].color!=LRM1_WRP)&&view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRL02Sy(){var ptrn;var msm;if (sL[LRM0]>0){ptrn=PTGRL0;msm=patC(ptrn,AIMR,1,1);}if (xn<0){ptrn=PTGRL2;msm=patC(ptrn,AIMR,1,1);}if (xn>=0){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRR0Sy(){var ptrn=PTGRR0;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (runUMLeaveRRTactic());} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRR2Sy(){var ptrn=PTGRR2;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (runUMLeaveRRTactic());}    return (rLostMSy(false));}function rUPSSy(){var ptrn=PTGRR1;var msm=patC(ptrn,AIMD,3,2);if (xn>=0){var c=CCW[xn+1];if (view[c].ant&&view[c].ant.friend&&(view[c].ant.food>0)){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}}if ((view[CCW[xn+2]].color==LMX_M3OUT)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&(mC!=LRR1X)){return {cell:POSC,color:LRR1X};} else if ((mT==AJM)&&(mC==LRR1U)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&LCRMX_OUT[view[CCW[xn+2]].color]){return {cell:POSC,color:LRR1V};} else if ((mC==LRR1X)||((mT==AJM)&&(mC==LRR1V))||((mC==LRR1U)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&LCRMX_IN[view[CCW[xn+2]].color])){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else if (mC!=LRR1U){return {cell:POSC,color:LRR1U};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return NOP;}}}return (rLostMSy(false));}function rUESSy(){var ptrn=PTMS0R_IN;var msm=patC(ptrn,AIMD,4,2);if (xn>=0){return (rUESTc(ptrn,msm));}return (rLostMSy(false));}function rUDSSy(){var ptrn;var msm;if ((sL[LML3]>=1)&&(sD[LMR2]+sD[LMR0]>=1)){ptrn=PTMS3;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(sL[LMR2]>=1)&&(sD[LML1]+sD[LML3]>=1)){ptrn=PTMS2;msm=patC(ptrn,AIMD,3,2);}if (xn>=0){if ((msm<0)&&(view[CCW[xn]].color==LRM0)&&(view[CCW[xn+1]].color==LRR0)&&(view[CCW[xn+2]].color==LMR0)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}return (rUDSTc(ptrn,msm));}if ((xn<0)&&(sL[LML1]>=1)&&(sD[LMR0]+sD[LMR2]>=1)){ptrn=PTMS1_IN;msm=patC(ptrn,AIMD,3,4);if (xn<0){ptrn=PTMS1;msm=patC(ptrn,AIMD,3,2);}}if (xn>=0){return (rUDSTc(ptrn,msm));}if ((sD[LML3]+sL[LMR0]>=2)&&(sD[LRL0] >=2)&&(sD[LML1]==0)){ptrn=PTMS0_WRAPPING;msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rUWRTc(ptrn,msm));}}if ((sL[LMR0]>=1)&&(sD[LML3]+sD[LML1]>=1)){ptrn=PTMS0;msm=patC(ptrn,AIMD,3,2);if (xn>=0){return (rUDSTc(ptrn,msm));}}if (spcRR1()){ptrn=PTGRR1;msm=patC(ptrn,AIMD,3,2);if (xn>=0){if (mC==LRR1){return {cell:POSC,color:LRR1U};}return NOP;}}if (spcMS0R()){ptrn=PTMS0R_IN;msm=patC(ptrn,AIMD,4,2);if (xn>=0){return (rUESTc(ptrn,msm));}}return (rLostMSy(false));}function rUSWSy(){var ptrn=PTMS0_WRAPPING;var msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rUWRTc(ptrn,msm));}return (rLostMSy(false));}function rURHSy(){return (rMNGTc());}function rUCRSy(){for (var i=TN; i>=1; i--){if (view[CCW[i]].ant&&dOK[CCW[i-1]]){return {cell:CCW[i-1]};}}return NOP;}function rLLLWSy(){var ptrn;var msm;if (mC==LML1){ptrn=PTMS1FL;msm=patC(ptrn,AIML,0,1);if (xn>=0){return (rLLLWTc());}} else if (mC==LML3){ptrn=PTMS3FL;msm=patC(ptrn,AIML,0,1);if (xn>=0){return (rLLLWTc());}} else if (sL[LML1]+sL[LML3]>=2){ptrn=PTMS0FL;msm=patC(ptrn,AIML,0,1);if (xn<0){ptrn=PTMS2FL;msm=patC(ptrn,AIML,0,1);}if (xn>=0){return (rLLLWTc());}} else if (spcMFR()){return (rLLRWSy());} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLLRWSy(){var ptrn;var msm;if (mC==LMR0){ptrn=PTMS0FR;msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLLRWTc());}} else if (mC==LMR2){ptrn=PTMS2FR;msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLLRWTc());}} else if (sL[LMR0]+sL[LMR2]>=2){ptrn=PTMS1FR;msm=patC(ptrn,AIMR,0,1);if (xn<0){ptrn=PTMS3FR;msm=patC(ptrn,AIMR,0,1);}if (xn>=0){return (rLLRWTc());}} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLASSy(){var ptrn;var msm;if ((sL[LML3]>=1)&&(sD[LMR2]+sD[LMR0]>=1)){ptrn=PTMS3;msm=patC(ptrn,AIMU,3,2);}if ((xn<0)&&(sL[LMR2]>=1)&&(sD[LML1]+sD[LML3]>=1)){ptrn=PTMS2;msm=patC(ptrn,AIMU,3,2);}if ((xn<0)&&(sL[LML1]>=1)&&(sD[LMR0]+sD[LMR2]>=1)){ptrn=PTMS1_IO;msm=patC(ptrn,AIMU,0,1);if (xn<0){ptrn=PTMS1;msm=patC(ptrn,AIMU,3,2);}}if (xn>=0){return (rLASTc(ptrn,msm));}if ((sD[LML3]+sL[LMR0]>=2)&&(sD[LRL0] >=2)&&(sD[LML1]==0)){ptrn=PTMS0_OUT;msm=patC(ptrn,AIMU,0,1);if (xn>=0){return {cell:CCW[xn+3],color:LCLR};}ptrn=PTMS0_WRAPPING;msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rLWRTc(ptrn,msm));}}if ((sL[LMR0]>=1)&&(sD[LML3]+sD[LML1]>=1)){ptrn=PTMS0;msm=patC(ptrn,AIMU,3,2);if (xn>=0){return (rLASTc(ptrn,msm));}}if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLSSy(){var ptrn=PTMS0R_OUT;var msm=patC(ptrn,AIMU,0,1);if (xn>=0){} else {ptrn=PTMS0R_IN;msm=patC(ptrn,AIMU,4,2);if (xn>=0){ptrn=PTMS0R_OUT;msm=patC(ptrn,AIMU,0,1);}}if (xn>=0){return (rLLSTc(ptrn,msm));} else if (spcMS()){return (rLASSy());} else {return (rLostMSy(false));}return NOP;}function rLLVSSy(){var ptrn=PTMS0R_OUT1;var msm=patC(ptrn,AIMU,0,1);if (xn>=0){if (view[CCW[xn+3]].color==LCLR){return {cell:CCW[xn+3],color:((mT==ASM) ? LMX_M2OUT : LMX_M1OUT)};
} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLDSSy(){var ptrn=PTGRR1;var msm=patC(ptrn,AIMU,1,1);if (xn>=0){if ((view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)){if ((mC==LRR1X)&&(view[CCW[xn+2]].color!=LMX_M3OUT)){return {cell:CCW[xn+2],color:LMX_M3OUT};}if ((view[CCW[xn+2]].color==LMX_M3OUT)&&(mC!=LRR1X)){return {cell:POSC,color:LRR1X};} else if ((LCRMX_OUT[view[CCW[xn+2]].color])&&
(mC!=LRR1V)){return {cell:POSC,color:LRR1V};} else if ((LCRMX_IN[view[CCW[xn+2]].color])&&(mC!=LRR1U)){return {cell:POSC,color:LRR1U};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}}return (rLostMSy(false));}function rLTRRSy(){return (rLCRTc());}function rLFRSy(){for (var i=1; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AE)&&dOK[CCW[i+2]]){return {cell:CCW[i+2]};}}return NOP;}function rLRHSy(){var ptrn=PTFRL1G;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLRLTc());}return (rMNGTc());}function rLLRL1Sy(){var ptrn=PTGRL1;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLRLTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLRL02Sy(){var ptrn;var msm;if (sL[LRM0]>0){ptrn=PTGRL0;msm=patC(ptrn,AIMR,1,1);}if (xn<0){ptrn=PTGRL2;msm=patC(ptrn,AIMR,1,1);}if (xn>=0){return (rLRLTc());}return (rLostMSy(false));}function rLLRR0Sy(){var ptrn=PTGRR0;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (rLRRTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLRR2Sy(){var ptrn=PTGRR2;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (rLRRTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLCRSy(){for (var i=TN; i>=1; i--){if (!dOK[CCW[i]]&&dOK[CCW[i-1]]){return {cell:CCW[i-1]};}}return NOP;}function rM2R1Sy(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)&&view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
(view[CCW[i+1]].ant.type==ASF)){if (i&1){} else {}if (dOK[CCW[i+7]]){return {cell:CCW[i+7]};} else {return NOP;}}}return (rLostMSy(true));}function rLostMSy(totally){if ((fdT>0)&&(mF==0)){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&dOK[CCW[i]]){return {cell:CCW[i]};}}}if (totally&(fT==0)){if (((mC==PY)&&(sN[PY]==0))||((mC==PR)&&(sN[PR]==0))){return {cell:POSC,color:PP};}if (((mC==PG)&&(sN[PG]==0))||((mC==PC)&&(sN[PC]==0))||((mC==PB)&&(sN[PB]==0))||((mC==PP)&&(sN[PP]==0))){return {cell:POSC,color:PW};} else if ((sT[PG]==0)&&(((mC==PK)&&(sN[PK]==0))||((mC==PY)&&(sN[PY]==0))||((mC==PR)&&(sN[PR]==0)))){return {cell:POSC,color:PW};} else if ((mC!=PW)&&(sN[mC]>=4)){return {cell:POSC,color:PW};}}if ((mC==PG)&&(sL[PG]>=2)){return {cell:POSC,color:PW};} else if (((mC==PK)||(mC==PR))&&(sN[PK]+sN[PR]>=3)){return {cell:POSC,color:PW};}if (sN[PW]<=4){var preferredColors =[PG,PB,PC,PP,PY,PR,PK];for (var ci=0; ci<preferredColors.length; ci++){var c=preferredColors[ci];if (mC==c){break;}if (sN[c]>0){for (var i=1; i<TN; i++){if ((view[CCW[i]].color==c)&&dOK[CCW[i]]){return {cell:CCW[i]};}}}}}if (RW){for (var i=1; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}for (i=0; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;} else {return NOP;}}function rDHSy(){if (mQ==0){var c=CCW[xn+2];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}c=CCW[xn+6];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}} else {var c=CCW[xn+4];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+3]].ant){return {cell:CCW[xn+3],color:LA};}c=CCW[xn+6];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}c=CCW[xn+5];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)){if (!view[CCW[xn+3]].ant){return {cell:CCW[xn+3],color:LA};} else if (!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}}}return NOP;}function rQSETc(){if (mC!=LT){return {cell:POSC,color:LT};}for (var i=0; i<TN; i++){if (view[CCW[i]].food>0){return {cell:CCW[i]};}}return NOP;}function rQSSTc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&(dOK[CCW[i]])){return {cell:CCW[i]};}}return NOP;}function rQSTCTc(){if ((mC!=LCLR)&&(sN[mC]>=4)){if (sN[LT]==0){return {cell:POSC,color:LT};} else if (sN[LT]>=3){return {cell:POSC,color:LT};} else {for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+2]].color!=LT)){return {cell:CCW[i+2],color:LT};}}return NOP;}} else if (sN[LT]==1){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+4]].color!=LCLR)){if (view[CCW[i+1]].color==LCLR){return { cell:CCW[i+1]};} else if (view[CCW[i+7]].color==LCLR){return { cell:CCW[i+7]};} else {return {cell:POSC,color:LT};}}}return {cell:POSC,color:LT};} else {return {cell:POSC,color:LT};}return NOP;}function rQSATc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LCLR)&&(view[CCW[i+1]].color==LCLR)&&(view[CCW[i+2]].color==LCLR)){if ((view[CCW[i+3]].color==LCLR)&&(view[CCW[i+4]].color==LCLR)){return {cell:CCW[i+2]};}return {cell:CCW[i+1]};}}for (i=TN-1; i>=0; i--){if (view[CCW[i]].color!=LT){return {cell:CCW[i]};}}for (i=0; i<TN; i++){if (view[CCW[i]].color!=LT){return {cell:CCW[i],color:LCLR};}}return {cell:0,color:LCLR};}function rQSEvTc(){if (sN[LT]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].color==LT){xn=i&6;}}if ( dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]] ){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+3]]&&dOK[CCW[xn+4]]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn]};} else {for (i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]&&dOK[CCW[i+3]]&&dOK[CCW[i+4]]){return {cell:CCW[i+2]};}}for (i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]){return {cell:CCW[i+1]};}}for (i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}return NOP;}function rQHTc(){var ptrn=PTHOME;var msm=patC(ptrn,POSC,0,1);if (msm!=0){var cc=fwdWrong[0];return {cell:cc.v,color:ptrn[cc.p]};} else {return NOP;}}function rGGTc(){var ptrn=PTGARDEN;var msm=patC(ptrn,POSC,0,1);if (msm!=0){var cc=fwdWrong[0];return {cell:cc.v,color:ptrn[cc.p]};} else {return NOP;}}function rUFCRTc(){var ptrn;var msm;if (mC==LRM0){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM2){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM1){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM1_WRP){ptrn=PTGRM1_WRP;msm=patC(ptrn,AIMR,1,1);}if ((xn<0)&&spcRR1()){return (rUPSSy());}if (xn<0){return (rLostMSy(false));}if (msm==0){if (fdL>0){if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if ((mC==LRM1)&&(view[CCW[xn+3]].color!=LRR1X)&&(view[CCW[xn+3]].color!=LRR1U)&&!((mT==AJM)&&(view[CCW[xn+3]].color==LRR1V))&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}return NOP;}for (var i=0; i<TN; i++){var ce=CCW[xn+i];if (view[ce].ant&&view[ce].ant.friend&&(view[ce].ant.type==AE)){if ((2<=i)&&(i<=4)){var msmSaved=msm;var fwdWrongSaved=Array.from(fwdWrong);var rearWrongSaved=Array.from(rearWrong);xn=xn % 4+4;msm=patC(ptrn,POSC,0,1);if (msm<msmSaved){xn=xn % 4+4;msm=msmSaved;fwdWrong=fwdWrongSaved;rearWrong=rearWrongSaved;} else {}break;}}}if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rUCRTc(){var ptrn;var msm;if (mC==LRM0){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&spcRR1()){return (rUPSSy());}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM2){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM1){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&(eT>0)){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM1_WRP){ptrn=PTGRM1_WRP;msm=patC(ptrn,AIMR,1,1);}if ((xn<0)&&spcRR1()){return (rUPSSy());}if (xn<0){return (rLostMSy(true));}if (msm==0){if (fdL>0){if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if ((mC==LRM1)&&(view[CCW[xn+3]].color!=LRR1X)&&(view[CCW[xn+3]].color!=LRR1U)){if ((((mT==AJM)&&(view[CCW[xn+3]].color==LRR1))||((mT==ASM)&&(view[CCW[xn+3]].color==LRR1V)))&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if (mC==LRM0&&(view[CCW[xn+5]].color==LRM1_WRP)&&!(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend)){return {cell:CCW[xn+5],color:LRM1};}var c=CCW[xn+5];if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){var evade=false;if (view[c].ant.food>0){evade=true;} else if (view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&(view[CCW[xn+1]].ant.food==0)){evade=true;}if (evade){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else {return NOP;}} else {return NOP;}}} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rUESTc(ptrn,msm){switch (view[CCW[xn+3]].color){case LMX_M0:return {cell:CCW[xn+3],color:LMX_M1IN};case LMX_M1OUT:if (mT==ASM){return {cell:CCW[xn+3],color:LMX_M2IN};}break;case LMX_M2OUT:if (mT==ASM){return {cell:CCW[xn+3],color:LMX_M3IN};}break;case LMX_M3OUT:break;case LMX_M1IN:case LMX_M2IN:case LMX_M3IN:if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if ((msm==0)&&dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {break;}default:break;}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}return NOP;}function runUMLeaveRRTactic(){if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}}function rUDSTc(ptrn,msm){var c=CCW[xn+1];if ((msm==0)&&(fdL>0)&&(view[CCW[xn+3]].food+view[CCW[xn+7]].food>0)){if (mC!=LMMF){return {cell:POSC,color:LMMF};} else if (view[CCW[xn+5]].color!=LMMH){return {cell:CCW[xn+5],color:LMMH};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};}} else if ((msm<0)&&!(view[c].ant&&view[c].ant.friend)){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>=0){if (dOK[c]){return {cell:c};} else {if (view[c].ant&&view[c].ant.friend){if (view[c].ant.food>0){if ((view[CCW[xn]].color==LCLR)&&dOK[CCW[xn]]){return {cell:CCW[xn]};} else if ((view[CCW[xn+2]].color==LCLR)&&dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else {var c=CCW[xn+5];if (view[c].ant&&view[c].ant.friend&&(view[c].ant.food==0)){if (view[c].color==LMMH){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else {return NOP;}} else if (mC!=LMMH){return {cell:POSC,color:LMMH};} else {return NOP;}} else {return NOP;}}} else {return NOP;}}}return NOP;}function rUWRTc(ptrn,msm){if (view[CCW[xn+3]].color!=LMS_WRP){return {cell:CCW[xn+3],color:LMS_WRP};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};}return NOP;}function rLLLWTc(){if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else {return NOP;}}function rLLRWTc(){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else {return NOP;}}function rLWRTc(ptrn,msm){if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else {return NOP;}}function rLASTc(ptrn,msm){var c=CCW[xn+5];if ((msm<0)&&!(view[c].ant&&view[c].ant.friend)){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (mC==LMMF){return {cell:POSC,color:LCLR};} else if (view[CCW[xn+5]].color==LMMH){return {cell:CCW[xn+5],color:LCLR};} else if (msm>=0){if (dOK[c]){return {cell:c};} else if ((view[c].food>0)&&(eT==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};}}}return NOP;}function rLLSTc(ptrn,msm){if (msm<0){if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend){return NOP;}var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}switch (view[CCW[xn+3]].color){case LMX_M1IN:return {cell:CCW[xn+3],color:LMX_M1OUT};case LMX_M2IN:return {cell:CCW[xn+3],color:LMX_M2OUT};case LMX_M3IN:default:return {cell:CCW[xn+3],color:LMX_M3OUT};case LMX_M1OUT:case LMX_M2OUT:case LMX_M3OUT:if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}break;}return NOP;}function rLCRTc(){var ptrn;var msm;var trust=(aF[AE]>0 ? 1 : 0);if (mC==LRM0){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM2){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM1){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM1_WRP){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);if (xn>=0){if (view[CCW[xn+3]].color!=LRR1X){return {cell:CCW[xn+3],color:LRR1X};} else if (!(view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend)){return {cell:POSC,color:LRM1};}}}if (xn<0){if (spcRR1()){return (rLDSSy());}return (rLostMSy(true));}if (msm==0){var c=CCW[xn+1];if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){var evade=false;if (view[c].ant.food==0){evade=true;} else if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].ant.food>0)){evade=true;}if (evade){if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else {return NOP;}} else {return NOP;}}} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rLRLTc(){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&
dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}function rLRRTc(){if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}function rMNGTc(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)){if (view[CCW[i]].color==LCLR){if (i&1){if ((view[CCW[i+3]].color==LG5)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};}} else {if ((view[CCW[i+4]].color==LG6)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if ((view[CCW[i+3]].color==LG5)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};}}return (rLostMSy(true));} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}}return NOP;}function rELGTc(){var ptrn=PTFRL1G;var msm;for (var i=0; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)){xn=i;break;}}msm=patC(ptrn,AIMU,0,1);if (xn<0){return NOP;} else if ((msm==0)&&dOK[CCW[xn+5]]&&((view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend)||
(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend))){return {cell:CCW[xn+5]};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {return NOP;}return NOP;}function rEBRTc(){var ptrn;var msm;if (mC==LRL0){for (var i=0; i<TN; i+=2){var c=CCW[i];if ((view[c].color==LRM0)&&view[c].ant&&view[c].ant.friend&&((view[CCW[i]].ant.type==AJM)||(view[CCW[i]].ant.type==ASM))){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);if (xn>=0){break;}}}if (xn<0){ptrn=PTFRL0;msm=patC(ptrn,AIMU,1,1);}if (xn<0){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRL1;msm=patC(ptrn,AIMU,1,1);}if (xn<0){return rECLRETc();}} else if (mC==LRL1){ptrn=PTFRL1;msm=patC(ptrn,AIMU,1,1);if ((xn<0)&&(eT>0)){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRL0;msm=patC(ptrn,AIMU,1,1);}if (xn<0){return rECLRETc();}} else if ((mC==LRR2)&&(sL[LRL1]>=1)&&(sL[LRL0]==0)){return {cell:POSC,color:LRL0};}if ((msm==0)&&dOK[CCW[xn+5]]&&((view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend)||
(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend))){return {cell:CCW[xn+5]};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {return NOP;}return NOP;}function rECLRETc(){var ptrn;var msm;for (var i=3; i<TN+2; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
((view[CCW[i]].ant.type==AJM)||(view[CCW[i]].ant.type==ASM))){xn=i-3;if (mC==LRL0){ptrn=PTFRL0;msm=patC(ptrn,AIMR,1,0.3);if (msm==PTNOM){ptrn=PTFRL2;msm=patC(ptrn,AIMR,1,0.3);}} else if (mC==LRL1){ptrn=PTFRL1;msm=patC(ptrn,AIMR,1,0.3);}if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}}return NOP;}function patC(ptrn,targetCell,qG,wt){if (xn>=0){return (patCO(ptrn,targetCell,qG,wt,xn));} else {var msm;for (var o=0; o<TN; o+=2){msm=patCO(ptrn,targetCell,qG,wt,o);if (xn>=0){return msm;}}return PTNOM;}}function patCO(ptrn,targetCell,qG,wt,ortn){var fwdFCs=FWD_CELLS[targetCell];var totDscs=0;fwdWrong=[];rearWrong=[];if ((Array.isArray(ptrn[POSC])&&!ptrn[POSC][mC])||
((ptrn[POSC]>0)&&(mC!=ptrn[POSC]))){if (fwdFCs[POSC]){fwdWrong.push({p:POSC,v:POSC});totDscs+=1;} else {rearWrong.push({p:POSC,v:POSC});totDscs+=wt;}}if ((xn<0)&&(totDscs>qG)){return PTNOM;}var jFrom=0;switch (targetCell){case AIMU:jFrom=4;break;case AIML:jFrom=6;break;case AIMR:jFrom=2;break;case AIMD:case POSC:default:break;}for (var j=jFrom; j<TN+jFrom; j++){var posP=CCW[j];var posV=CCW[ortn+j];var c=view[posV].color;if ((Array.isArray(ptrn[posP])&&!ptrn[posP][c])||
((ptrn[posP]>0)&&(c!=ptrn[posP]))){if (fwdFCs[posP]){fwdWrong.push({p:posP,v:posV});totDscs+=1;} else {rearWrong.push({p:posP,v:posV});totDscs+=wt;}}if ((xn<0)&&(totDscs>qG)){return PTNOM;}}if ((xn<0)){xn=ortn;}if (fwdWrong.length==0){return (totDscs);} else {return (-totDscs);}}function isQc0(color){return (LCRQCVAL[color]&&(LCRQC_VALUE[color]==0));
}function isQc2(color){return (LCRQCVAL[color]&&(LCRQC_VALUE[color]==2));
}function incQc(color){if (LCRQCVAL[color]){if (LCRQC_VALUE[color]>=QCPERD){return LCRQC[0];} else {return (LCRQC[(LCRQC_VALUE[color]+1) % QCPERD]);
}} else {return undefined;}}function isSc0(color){return (LCRSCVAL[color]&&(LCRSC_VALUE[color]==0));
}function isSc1(color){return (LCRSCVAL[color]&&(LCRSC_VALUE[color]==1));
}function incSc(color){if (LCRSCVAL[color]){return (LCRSC[(LCRSC_VALUE[color]+1) % SCPERD]);
} else {return undefined;}}function spcMS(){return (((mC==LCLR)||((mF+fdL>0)&&(mC==LMMF))||((mF>0)&&(mC==LMMH)))&&(sN[LMR0]+sN[LML1] +sN[LMR2]+sN[LML3]>=2)&&(sN[LCLR]>=3)&&(sN[LMMF] +sN[LMMH] +sN[PB]<=3)); }function spcRM(){return (LCRGRM_ALL[mC]&&(sT[LRL0]+sT[LRL1]>=3)&&(sN[LRL0]>=1)&&(sN[LRR0]+sN[LRR2]>=2)&&(sT[LRM0]+sT[LRM1_WRP] +sT[LRM1]+sT[LRM2]>=2)&&(sT[LCLR]<=4));}function spcRL1(){return ((mC==LRL1)&&(sL[LRL0]>=2)&&(sD[LRM0]>=1)&&(sL[LRM1_WRP]+sL[LRM1]>=1)&&(sD[LRM2]>=1));}function spcRL02(){return ((mC==LRL0)&&(sL[LRL1]+sL[LRL2]>=2)&&(sN[LRM0]>=1)&&(sD[LRM1_WRP]+sD[LRM1]>=1));}function spcRR0(){return ((mC==LRR0)&&(sL[LRM1]==0)&&(sD[LRM1]+sD[LRM1_WRP]>=1)&&(sL[LMR0]>=1)&&(sL[LRR2]>=1));}function spcRR1(){return (LCRGRR1[mC]&&(sN[LRR0]>=2)&&(sL[LRR2]>=1)&&(sD[LRM0]>=1)&&(sN[LCLR]<=3)&&(sL[LRM1] +sL[LRM1_WRP]>=1));}function spcRR2(){return ((mC==LRR2)&&(sD[LCLR]>=1)&&(sD[LRM0]>=1)&&(sD[LRM1]+sD[LMR0]>=2)&&(sL[LRR0]>=2));}function spcMS0R(){return((mC==LCLR)&&(sL[LMR0]>=1)&&(sL[LRR1U]>=1)&&(sD[LRR2]>=1)&&(sD[LRR0]>=1));}function spcMS0ROut(){return ((mC==LCLR)&&(sL[LMR0]+sL[LRR1V]>=2)&&(sD[LRR2]>=2)&&(sD[LRR0]>=1));}function spcMS0W(){return ((mC==LCLR)&&(sD[LRL0]>=3)&&(sL[LRL1]>=1)&&(sL[LMS_WRP]>=2)&&(sN[LCLR]>=2));}function spcMFL(){return ((sL[LMMF]>=1)&&(sD[LMMH]>=1)&&(sT[LCLR]>=2)&&(sT[LML1]+sT[LML3]>=1));}function spcMFR(){return ((sL[LMMF]>=1)&&(sD[LMMH]>=1)&&(sT[LCLR]>=2)&&(sT[LMR0]+sT[LMR2]>=1));}function fixup(ptrnCell){if (Array.isArray(ptrnCell)){for (var i=1; i<=9; i++){if (ptrnCell[i]){return i;}}return LCLR;} else {return ptrnCell;}}

(trichoplax의 및 dzaima의 조언에 -하는 많은 덕분에 -이 가독성을 희생의 PPCG 크기 제한에 맞도록 uglified되었습니다!. 편집 : 무삭제 원본, 충분히 주석과 의미있는 변수와 함수 이름을 가진, 지금 가능 GitHub에서 .)

일반적인 초기 스크램블 후 Windmill Queen은 세 개의 레일을 시작 하여 더 가까운 영역을 더 철저히 닦고 레일 이동 시간을 줄이고 중복성을 추가하는 것을 목표로합니다. 네 번째면에는 작은 정원이 있으며 열매는 빨간색과 파란색과 검은 색입니다.

우리는 Rail 's Repairer에서 광부를 배제합니다. (매우 긴 레일은 혼합 된 축복입니다. 뱀파이어를 끌어들이는 경향이 있습니다.) 대신, 우리는 각 레일에 엔지니어가 있습니다. 원래의 목적은 광부에게 레일을 연장하는지 (즉, 엔지니어를 볼 수있을 때) 수리하는 것이 아니라 수리 할 수 ​​없는지를 알려주는 것이었지만 코드가 발전함에 따라 다소 묻어났습니다. 그들은 이제 레일이 거꾸로 연속되는 것을 막는 것과 같은 몇 가지 사소한 작업을 돌 보았습니다.

너비가 1000 셀, 깊이가 3 셀인 샤프트는 평균 3 개의 음식을 함유 할 것으로 예상되며,이 깊이의 모든 샤프트 중 4 %만이 함유하지 않습니다. 일단 우리가 레일이 그 가치가있을만큼 충분히 길어 졌다고 저장 한 음식의 양을 추정하면, 여왕은 이전에 광부가 탐험했던 샤프트를 다시 검사 할 선임 광부를 생성하기 시작할 것입니다. 광부 위의 광부에서와 같이 경기장 주위를 가로 지르는 샤프트를 레일의 뒤쪽 (왼쪽)으로 처리 할 준비가되었습니다.

윈드밀 퀸은 또한 정원사와 비서라는 두 명의 다른 직원을 고용하고 있습니다. 그들은 같은 개미 유형이며, 여왕과 서로에 대한 위치에 따라 하나 또는 다른 것을합니다. 그들은 여왕이 엔지니어와 처음 몇 명의 광부 창설자를 조율하고 여왕이 시계를 달릴 수 있도록 도와줍니다.

이 마스터 시계는 비축 된 음식의 양과 우리가받는 임의의 1-4 방향과 함께 음식 도착에서 광부 생성을 분리하고 추가 광부 생성 속도를 조절합니다. 여왕이 막 정착했을 때, 들어오는 음식의 비율이 1000 이동 당 약 9에 도달 할 때까지 (약 12 개의 생산적인 광부를 필요로 할 때까지) 모든 들어오는 음식은 빠르게 더 많은 광부로 전환됩니다. 그런 다음 클럭 사이클이 제한 요인이되고 음식을 저장하기 시작합니다. 나중에 음식의 양이 증가함에 따라, 우리는 산란 속도를 1000 이동 당 최대 6 개의 새로운 광부와 최대 3 개의 이동으로 제한하고 결국에는 생성을 완전히 중단합니다. 래칫 메커니즘은 모든 레일이 막히거나 손상되었을 때 여왕이 산란시 너무 많은 음식을 소비하지 못하게합니다.

큰 피해가 없어도 각 게임이 전개 될 때 채굴 효율이 크게 떨어집니다. 초기에 우리는 광속을 반 광속으로 시추하고 광속으로 돌아와 평균 1000 이동마다 1 개의 음식을 제공 할 것으로 예상합니다. 마지막으로, 1000 이동 당 광부 당 0.12-0.14 음식과 비슷합니다. 더 긴 레일을 여행하고 대부분 흰색 샤프트 패턴을 더 이상 흰색 캔버스에 칠하지 않고 샤프트와 레일을 복구하는 데 시간이 걸립니다. 광부들은 상대방과 페인트 볼 싸움에 갇히거나 길을 잃거나 묶여 있습니다.

우리 광부는 주요 교통 정체에서 스스로를 추출하기 위해 노력합니다.

그리고 비우호적 인 침입자를 다루는 초보적인 면역 체계가 있습니다.

뒷마당에서 스팀 롤을 시도하는 것은 권장되지 않습니다. 우리 직원들은 즐겁지 않을 것입니다.

가장 큰 단점은 풍차 여왕이 초기 직원을 주머니에서 꺼내기 위해 8 개의 음식이 필요하다는 것입니다. 따라서 스크램블링 단계가 다소 길어 다른 경쟁자들에게 먼저 출발합니다. 만약 우리가 음식을 비축하기 전에 우리 둥지가 오버런되고 레일이 지워지면, 그날은 우리를 위해 심하게 끝날 것입니다. 나중에, 적어도 하나의 레일이 작동하거나 수리가 가능할 때, 우리는 보통 우리가 이미 가지고있는 것을 계속 유지하거나 최소한 (대부분) 붙잡을 수 있습니다.

이 구현에서는 인접 셀을 모퉁이에서 시작하여 시계 반대 방향으로 번호가 매겨진 것으로 취급하고 ( CCW) 이러한 숫자를 컨트롤러의 view아래 첨자 로 변환합니다 . 우리가 북쪽에 대한 감각을 고정시킬 필요가 있고 가능할 때, 우리는 나침반을 기본 첨자로 설정합니다CCW. 개미 기능은 항상 주변 환경을 비축하여 시작합니다. 특히 스펙트럼을 기록하는 빈도 (각 색상이 발생하는 빈도)를 기록한 다음 전략 및 전술의 다단계 의사 결정 트리를 따라 개미 유형 및 상황별로 분기합니다. 이를 통해 가장 일반적인 상황을 매우 신속하게 처리하면서 여러 가지 이상한 특수 사례를 처리 할 수 ​​있습니다. 나무에는 거의 200 개의 잎이있어 세포에 페인트를 바르거나 개미를 만들거나 개미를 만듭니다. 70 개 이상은 2 ^ 27 개의 가능한보기 색상 패턴과 가능한 개미,보기에있는 음식 및 음식을 곱한 값에서 증류됩니다. 수행했다.

다음은 허브 지오메트리의 ASCII 렌더링입니다.

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   | ^ |MR2|   | v |MR2|   | ^ |   |   |   |   |   |   |   |   |
|   |   |   |   | i |   |   | a | r |  rail 2   |   |   |   |   |   |   |   |
+---+---+---+---+-n-+---+---+-c-+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |ML1|   |   |ML1| a |   |RL0|RM0|RR0|   |   |   |   |   |   |   |
|   |   |   | y | u |   | y | t |   | c | r | g |   |   |   |   |   |   |   |
+---+---+---+---+-s-+---+---+-e-+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |MX | e |MR0|MX | d |MR0|RL2|RM2|RR2|MX |ML1|   |ML3|   |ML1|   |
|   |   |   | c |   | k | y |   | k | c | g | y | c | y |   | c |   | y |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |RR1|RR0|RR2|RR1|RR0|RR2|RR1|RR0|RL1|RM1|RR1|   | shaft in use  |  >|   |
|  r|   | g | y | r | g | y | y | g | g | b | r |   |   |   |   |   |   |   |
+--a+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| <i|RM1|RM0|RM2|RM1|RM0|RM2|RM1|RM0|RL0|RM0|RR0|MR0|   |MR2|   |MR0|   |   |
|  l| b | r | g | b | r | g | b | r | c | r | g | k |   | r |   | k |   |   |
+-- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|  3|RL1|RL0|RL2|RL1|RL0|RL2|RL1|RL0|*Q*|RL0|RL1|RL2|RL0|RL1|RL2|RL0|RL1|   |
|   | g | c | c | g | c | c | g | c |clk| c | g | c | c | g | c | c | g |r  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+a--+
|   |   |   |   |   |   |   |G3 |Grd|Sec|RM0|RM1|RM2|RM0|RM1|RM2|RM0|RM1|i >|
|   |   |   |   |   |   |   | k |r/y|clk| r | b | g | r | b | g | r | b |l  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ --+
|   |   |   |   |   |   |   |G4 |G5 |G6 |RR0|RR1|RR2|RR0|RR1|RR2|RR0|RR1|1  |
|   |   |   |   |   |   |   | r | k | b | g | y | y | g | r | y | g |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |MR0|   |MX |MR0|   |MX |   |   |   |
|   |   |   |   |   |   |   |   |   |   | k |   | y | k |   | c |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

(후배 광부가 첫 하강 중과 후 MX 및 RR1 색상 표시).

수십 개의 느슨한 끝이 있습니다. (예를 들어, 우리는 철로를 채굴하는 데 방해가 될 수 있기 때문에 음식을 깨끗하게 정리하지만, 여분의 복잡성은 그 가치가 없어 보이기 때문에 철로를 벗어난 음식은 먹지 않을 것입니다.) 더 나은의 적 ...

v1.1 은 실격의 원인을 수정하고 몇 가지 사소한 개선 사항을 추가합니다.

v1.2 에는 몇 가지 수정 사항과 향상된 기능이 추가되었습니다.

v1.3varDave 와 같은 엄격 모드 컨트롤러에서 작동하도록 이전에 혼합 선언을 추가합니다 . 기능적인 변화가 없습니다.

v1.4 는 마늘 사용에 대한 여왕과 정원사 사이의 오해를 수정하고 (레일 3을 따라 도착하는 뱀파이어가 알아낼 예정 임), 어리석은 패턴 정의 버그를 치료하고 몇 가지 경우를 개선합니다.

v1.5 는 풍차에게 새로운 트릭을 가르칩니다-개미를보고 싶습니까?

v1.6을 사용하면 광부가 패턴을 광대 한 녹색 창으로 낙서하고 집에서 도난 경보를 개선하며 약간 더 탄력적 인 방식으로 다른 곳의 적 여왕을 다루며 약간의 터치 업을 할 수 있습니다.

약간의 탄력성 수정을 제외하고 v1.7Lightspeed 스타일의 시작 단계를 사용하여 조기에 정착하는 것이 아니라 더 많은 양의 식품에 정착합니다. (우리는 광속 탠덤의 예상 음식 반환 속도를 초과하기 위해 7 명의 광부가 필요하므로 광업으로 전환하기 전에는 광업으로 전환 할 필요가 없습니다.)

v1.8 은 Lightspeed-phase 로직의 교착 상태를 수정하고 더 중요한 것은 v1.6에서 도입 된 스폰 버그를 수정하여 실격을 초래했습니다.

v1.9 는 또 다른 이국적인 자격 박탈 버그를 수정하고 일시적으로 샤프트의 일부 혼잡 사례를 해결하고 최신 뱀파이어 발명을 다루려고 시도합니다.

v2.0을 사용하면 여왕은 광속 스타일 스크램블링에 의존하고 나중에 원래 장소에서 멀리 떨어진 다른 곳에서 새로운 공장을 찾기 위해 운이 다시 정착하여 필요로 할 때 기존 허브를 완전히 버릴 수 있습니다. 반면에 가변 속도 식품 제어 발진기를 사용한 실험에서는 확실한 개선이 이루어지지 않았습니다. 더 많은 광부를 더 빨리 보내면 일부 경쟁사의 사고율은 물론 우리 자신도 증가 할 것입니다. FCO 코드는 그대로 유지되지만 현재는 비활성화되어 있습니다.

v2.1 은 근로자가 체재하는 것보다 더 나은 움직임을 보인 3 가지 주요 사례를 다룬다.


광부의 샤프트가 왜 그런지 이유는 트레일 소거 때문입니다. 제 설계에서 샤프트를 찾는 트레일 소거로 인해 레일로 돌아가는 경우는 거의 없지만, 50 % 이상의 확률이 있습니다. 트레일 지우개를 레일로 이끄는 나는 하나를 찾지 않고 적어도 30 분 동안 더 나은 샤프트 패턴을 찾고있었습니다 ..
dzaima

그래, 요점이야 반면 트레일 지우개는 레일로 지루해질 수 있고 지그재그 백투백 샤프트 벽을 따라 걸을 수 있습니다 . 교대 패턴은 어려운 지형으로 드릴링 할 때 더욱 강력합니다 (완전하지는 않지만).
GNiklasch

레일 위의 광부들은 때때로 트레일 소 거기 (Trail-eraser)의 혜택을받습니다 : 레일의 광부는 실제로 의도하지 않고 샤프트를 재 탐사 할 수 있습니다.-그리고 레일과 샤프트를 수리 할 수 ​​있습니다. 사고는 일어날 수 있고 일어날 것이다. 복구 옵션이 중요합니다. MoaR은 이미 인상적입니다!
GNiklasch

1
나는 설명을 좋아한다. 특히 하나의 작업자 유형을 사용하여 로컬 컨텍스트에 따라 서로 다른 두 가지 동작을 생성합니다.
trichoplax

1
@trichoplax Whoops-헤드 업 주셔서 감사합니다! 알려진 원인 (아래 첨자 2 개), cf issue # 6 . 이 기회를 사용하여 몇 가지 다른 작은 수정 사항을 체크인하겠습니다. 회귀 테스트 후 코드를 다시 축소 한 후 답변을 업데이트합니다.
GNiklasch

12

블랙홀

var COLOR=8
var COLOR2=7
var COLOR3=2
var LOCKDOWN=8
var orthogonals = [1, 3, 7, 5]
var isQueen = view[4].ant.type==5
var rotationsCW = [1,2,5,8,7,6,3,0]
var rotationsCCW = [3,6,7,8,5,2,1,0]
var matchStates = [
    {state:[0,0,0,
            0,1,0,
            0,0,0],move:0,back:0,fill:true},
    {state:[1,0,0,
            0,1,0,
            0,0,0],move:1,back:3,fill:true},
    {state:[0,1,0,
            1,0,0,
            0,0,0],move:0,back:0,fill:false},
    {state:[0,1,0,
            0,0,1,
            0,0,0],move:2,back:2,fill:false},
    {state:[0,0,1,
            0,0,1,
            0,1,0],move:8,back:2,fill:false},
    //5:
    {state:[1,0,0,
            1,0,0,
            0,1,0],move:2,back:6,fill:false},
    {state:[0,1,0,
            0,1,0,
            0,0,0],move:2,back:0,fill:false},
    {state:[1,0,0,
            1,1,0,
            0,0,0],move:1,back:6,fill:false},
    {state:[0,1,1,
            0,1,0,
            0,0,0],move:5,back:0,fill:false},
    {state:[0,1,0,
            1,1,0,
            0,0,0],move:2,back:6,fill:false},
    //10:
    {state:[1,1,0,
            0,1,0,
            0,0,0],move:2,back:3,fill:false},
    {state:[1,1,0,
            1,1,0,
            0,0,0],move:2,back:6,fill:false},
    {state:[0,1,1,
            0,1,1,
            0,0,0],move:8,back:0,fill:false},
    {state:[1,1,1,
            0,1,0,
            0,0,0],move:5,back:3,fill:false},
    {state:[1,0,0,
            1,1,0,
            1,0,0],move:1,back:7,fill:false},
    //15:
    {state:[0,1,0,
            1,1,1,
            0,0,0],move:8,back:6,fill:false},
    {state:[1,1,1,
            1,1,0,
            0,0,0],move:5,back:6,fill:false},
    {state:[1,0,0,
            1,1,0,
            1,1,0],move:1,back:8,fill:false},
    {state:[1,1,0,
            1,1,0,
            1,0,0],move:2,back:7,fill:false},
    {state:[1,1,1,
            0,1,1,
            0,0,0],move:8,back:3,fill:false},
    //20:
    {state:[1,1,1,
            0,0,1,
            0,0,1],move:7,back:3,fill:true},
    {state:[1,1,1,
            1,0,0,
            1,0,0],move:5,back:7,fill:true},
    {state:[1,0,0,
            1,0,0,
            1,1,1],move:1,back:5,fill:true},
    {state:[0,0,1,
            0,0,1,
            1,1,1],move:3,back:1,fill:true},
    {state:[1,1,1,
            0,1,1,
            0,0,1],move:7,back:3,fill:true},
    //25:
    {state:[1,1,1,
            1,1,0,
            1,0,0],move:5,back:7,fill:true},
    {state:[1,0,0,
            1,1,0,
            1,1,1],move:1,back:5,fill:true},
    {state:[1,1,1,
            1,1,1,
            0,0,0],move:8,back:6,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,0,0],move:8,back:7,fill:true},
    {state:[1,1,1,
            1,1,0,
            1,1,0],move:5,back:8,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,1,0],move:8,back:8,fill:true},
    //30:
    {state:[1,1,1,
            1,1,1,
            1,0,1],move:7,back:7,fill:true},
    {state:[1,1,1,
            1,1,0,
            1,1,1],move:5,back:5,fill:true},
    {state:[1,0,1,
            1,1,1,
            1,1,1],move:1,back:1,fill:true},
    {state:[1,1,1,
            0,1,1,
            1,1,1],move:3,back:3,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,1,1],move:9,back:9,fill:false},
    //35:
]
function matchesColor(c) {
    return c==COLOR || c==COLOR2 || c==COLOR3 || (view[4] == COLOR3 && c == LOCKDOWN)
}
function matchesNonLineColor(c) {
    return c==COLOR || c==COLOR2
}
function isAnyColor(c) {
    var r=0
    for(var i=0;i<9;i++) {
        if(view[i].color == c) r++
    }
    return r
}
function howManyAnts() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(view[i].ant != null) r++
    }
    return r
}
function deRotate(m, amt) {
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8]
    amt = -amt
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8]
}
function deRotateSide(m, amt) {
    return deRotate(m,amt*2)
}
function matchWhileLost(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(view[i].color == COLOR3) c++
        if(view[i].color == COLOR3 && i%2 == 0) c+=10
    }
    if(c == 2) {
        if(view[0].color == COLOR3 || view[2].color == COLOR3 || view[6].color == COLOR3 || view[8].color == COLOR3) {
            return {cell:4,color:COLOR3}
        }
        if(view[0].ant == null)
            return {cell:0}
        if(view[2].ant == null)
            return {cell:2}
        if(view[6].ant == null)
            return {cell:6}
        if(view[8].ant == null)
            return {cell:8}
    }
    c = 0
    sides[4] = 0
    var toMatch =[{state:[1,1,1,
                         2,0,2,
                         0,1,0]},
                 {state:[0,2,1,
                         1,0,1,
                         0,2,1]},
                 {state:[0,1,0,
                         2,0,2,
                         1,1,1]},
                 {state:[1,2,0,
                         1,0,1,
                         1,2,0]}]
    for(var m=0;m<4;m++) {
        var score=0
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(sides[j] == COLOR3 && toMatch[m].state[j] == 1) {
                    score++
                }
                if(sides[j] != COLOR3 && (toMatch[m].state[j] == 0 || toMatch[m].state[j] == 2)) {
                    score++
                }
                if(sides[j] == COLOR3 && toMatch[m].state[j] == 2) {
                    score--
                }
            }
        }
        if(score >= 6) {
            var clearOrder=[1,0,2]
            for(var r=0;r<clearOrder.length;r++) {
                var s = deRotateSide(clearOrder[r],m)
                if(view[s].color == COLOR3) {
                    if(view[s].ant == null)
                        return {cell:s,color:COLOR}
                    else
                        return {cell:4}
                }
            }
        }
    }
    return null
}
function matchBlueStyle(sides) {
    return null
}
function bestMatch(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(sides[i] > 1) c++
    }
    if(!isQueen && view[4].ant.food > 0) {
        c++
        sides[4] = 8
    }
    if(c <= 1) {
        return {state:matchStates[0],rot:0,fill:matchStates[0].fill}
    }
    c = 0
    while(!matchesColor(sides[0]) && !matchesColor(sides[1]) && c < 4) {
        var s2 = [0,0,0,0,0,0,0,0,0]
        s2[0] = sides[2]
        s2[1] = sides[5]
        s2[2] = sides[8]
        s2[3] = sides[1]
        s2[5] = sides[7]
        s2[6] = sides[0]
        s2[7] = sides[3]
        s2[8] = sides[6]
        sides = s2
        c++
    }
    while(c < 8 && (matchesColor(sides[0]) || matchesColor(sides[1])) && matchesColor(sides[8])) {
        var s2 = [0,0,0,0,0,0,0,0,0]
        s2[0] = sides[2]
        s2[1] = sides[5]
        s2[2] = sides[8]
        s2[3] = sides[1]
        s2[5] = sides[7]
        s2[6] = sides[0]
        s2[7] = sides[3]
        s2[8] = sides[6]
        sides = s2
        c++
    }
    var bestState = null
    var bestMatchScore = -1
    for(var i = 0; i < matchStates.length; i++) {
        var score=0
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(matchesColor(sides[j]) && matchStates[i].state[j] == 1) {
                    score++
                }
                if(!matchesColor(sides[j]) && matchStates[i].state[j] == 0) {
                    score++
                }
            }
        }
        if(score >= bestMatchScore) {
            //console.log("state " + i + ": " + score);
            bestMatchScore = score
            bestState = matchStates[i]
        }
    }
    return {state:bestState,rot:c,fill:bestState.fill,score:bestMatchScore}
}
function getHighestWorker() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type > r) r = view[i].ant.type
        }
    }
    return r
}
function pathLost() {
    var i, j
    var safe = []
    for(var q=0;q<9;q++) {
        if(q != 4 && view[q].ant != null && view[q].ant.friend && (view[q].ant.type > view[4].ant.type && view[4].ant.food == 0 && view[q].ant.type < 5)) {
            if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
            return {cell:4}
        }
    }
    if (matchesNonLineColor(view[4].color)) {
        var myView = [0,0,0,0,0,0,0,0,0]
        for(var i=0; i < 9; i++) {
            myView[i] = view[i].color
            if(!isQueen && view[4].ant.food > 0 && view[i].food > 0) {
                myView[i] = COLOR;
            }
        }
        var ret = matchWhileLost(myView)
        if(ret == null)
            return {cell:4, color:COLOR3}
        else {
            if(!(view[ret.cell].ant != null && view[ret.cell].ant.friend == false) && (view[4].ant.food == 0 || view[ret.cell].food == 0 || isQueen))
                return ret
        }
    }
    for (i=0; i<view.length; i++) {
        if (view[i].ant === null && (view[4].ant.food == 0 || view[i].food == 0 || isQueen)) {
            safe.push(i);
        }
    }
    for (i=0; i<4; i++) {
        j = (i+2) % 4
        if (matchesNonLineColor(view[orthogonals[i]].color) && view[orthogonals[j]].color == COLOR3) {
            if (view[orthogonals[i]].ant == null) {
                return {cell:orthogonals[i]}
            } else if (safe.length > 0) {
                return {cell:safe[0]}
            } else if (view[0].ant === null && (view[4].ant.food == 0 || view[0].food == 0 || isQueen)) {
                return {cell:0}
            }
        }
    }
    if (view[1].ant === null && (view[4].ant.food == 0 || view[1].food == 0 || isQueen)) {
        return {cell:1}
    } else {
        if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
        return {cell:4}
    }
}
function isAllyAdjacentTo(view, place) {
    var i = deRotate(place, 1)
    var j = deRotate(place, -1)
    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type < 5) return 1
    if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return 1
    if(orthogonals.indexOf(place) >= 0) {
        i = deRotate(place, 2)
        j = deRotate(place, -2)
        if(view[i].ant != null && view[i].ant.friend && view[i].ant.type < 5) return 2
        if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return 2
    }
    return 0
}
function findOpenSpace(pos, dir) {
    if(pos > 8 || pos < 0) return pos
    if(view[pos].ant != null && view[pos].ant.friend && view[4].ant.food == 0) {
        pos=deRotate(pos,4)
    }
    //var inc = dir>0?1:-1
    var b = 0
    while(view[pos].ant != null && b < 8) {
        pos=deRotate(pos,dir)
        b++
    }
    return pos
}
//end functions
function getReturn() {
    var colToPlace=COLOR
    var blueAmt = isAnyColor(COLOR2)
    var myView = [0,0,0,0,0,0,0,0,0]
    for(var i=0; i < 9; i++) {
        myView[i] = view[i].color
        if(!isQueen && view[4].ant.food > 0 && view[i].food > 0) {
            myView[i] = COLOR;
        }
        if(!isQueen && view[4].ant.food == 0 && view[i].ant != null && view[i].ant.food > 0) {
            if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
            return {cell:4};
            //myView[i] = COLOR;
        }
        if(view[i].ant != null && !view[i].ant.friend) {
            myView[i] = COLOR;
        }
    }
    if(isQueen) {
        for(var i=0; i < 9; i++) {
            if(i != 4 && !matchesColor(view[i].color) && view[i].ant != null) {
                myView[i] = COLOR
            }
        }
    }
    //console.log("view:")
    //console.log(myView)
    //console.log("1")
    var match = bestMatch(myView)
    if(match.state.move != 9) {
        var ctY = 0
        var lastY = -1
        var ctW = 0
        var lastW = -1
        for(var i=0; i < 9; i++) {
            if(view[i].color == COLOR3) {
                myView[i] = 8
                ctY++
                lastY = i
            }
            else if(!matchesColor(view[i].color)) {
                ctW++
                lastW = i
            }
        }
        if(ctY > 0 && isQueen && view[4].ant.food > 0 && ctW >= 1) {
            if(view[4].color != COLOR3 && matchesColor(view[4].color))
                return {cell:4,color:COLOR3}
            var tt = deRotate(lastW,-1)
            if(view[tt].color != COLOR2)
                return {cell:tt,color:COLOR2}
            lastW = findOpenSpace(lastW,1)
            return {cell:lastW}
        }
        else if(ctY >= 2 && ctW >= 3)
            match = bestMatch(myView)
        else if(ctY > 0 && view[lastY].ant == null && ctW >= 3) {
            return {cell:lastY,color:1}
        }
    }
    //console.log("2")
    if(!isQueen) {
        for(var i=0; i < 9; i++) {
            if(view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 0 && view[i].ant.food <= 2) {
                if(view[4].ant.type == 4)
                    return {cell:4,color:COLOR2}
                return {cell:4}
            }
        }
    }
    //console.log("3")
    if(blueAmt > 0 && view[4].color != COLOR3 && match.state.move != 9) {
        //console.log("Some blue")
        var mb = match.state.back
        mb = deRotateSide(mb,match.rot)
        if(!isQueen || view[4].ant.food <= 2) {
            var a = deRotate(mb,1)
            var b = deRotate(mb,-1)//TODO should be -1
            //console.log("mb: " + mb + "," + a + "," + b)
            if(mb != 9 && (view[mb].color == COLOR2 || view[4].color == COLOR2 || view[a].color == COLOR2 || view[b].color == COLOR2)) {
                //blue behind
                //console.log("Blue behind")
                colToPlace = COLOR2
            }
            else {
                //console.log("No blue behind")
                //console.log(match)
                var myView2 = [0,0,0,0,0,0,0,0,0]
                //construct a view without blue in it
                for(var i=0; i < 9; i++) {
                    myView2[i] = view[i].color == COLOR2?1:view[i].color
                }
                var match2 = bestMatch(myView2)
                if(match2.state.move == 9 || match2.state == matchStates[0]) {
                    //zero or one black
                    //console.log("<= 1 Black")
                    //console.log(myView2)
                    //console.log(match2.state)
                    colToPlace = COLOR2
                }
                else if(view[4].ant.type != 4) {
                    var mf = match2.state.move
                    mf = deRotateSide(mf,match2.rot)
                    //console.log("mf: " + mf)
                    if(mf != 9 && view[mf].color == COLOR2 && view[mf].ant == null) {
                        //about to move onto blue
                        //console.log("Moving onto blue")
                        //console.log(view)
                        //console.log(myView2)
                        return {cell:mf,color:1}
                    }
                    var clearOrder=[1,3,5,7,0,2,6,8]
                    for(var r=0;r<clearOrder.length;r++) {
                        var s = deRotateSide(clearOrder[r],0)
                        if(view[s].color == COLOR2 && (view[s].ant == null || !view[s].ant.friend || (isQueen && view[4].ant.food == 0))) {
                            //console.log("DIE BLUE SCUM")
                            //console.log(view)
                            //console.log(myView2)
                            return {cell:s,color:1}
                        }
                        else if(isQueen && view[s].ant != null && view[s].ant.friend) {
                            //console.log("Blue Queen")
                            //console.log(view)
                            //console.log(myView2)
                            return {cell:4,color:COLOR2}
                        }
                    }
                }
            }
        }
        //console.log("Nothing happened")
    }
    //console.log("4")
    if(view[4].ant.type <= 2) {
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && !view[i].ant.friend) {
          var canSeeAlly = isAllyAdjacentTo(view,i)
          if(canSeeAlly == 0) {
            if(view[i].color == LOCKDOWN) {
              var a = deRotate(i, 1)
              var b = deRotate(i, -1)
              if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
              if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              if(orthogonals.indexOf(i) >= 0) {
                a = deRotate(i, 2)
                b = deRotate(i, -2)
                if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
                if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              }
            }
            else {
              return {cell:i,color:LOCKDOWN}
            }
            if(view[4].color == LOCKDOWN || view[4].color == COLOR) {
              var ii = deRotate(i,4)
              ii = findOpenSpace(ii,1)
              return {cell:ii}
            }
            return {cell:4,color:COLOR}
          }
          else if(canSeeAlly == 2) {
            var m = deRotate(i, 2)
            var j = deRotate(i, -2)
            if(view[m].ant != null && view[m].ant.friend && view[m].ant.type < 5) return {cell:m,color:LOCKDOWN}
            if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return {cell:j,color:LOCKDOWN}
          }
          else if(view[4].color == LOCKDOWN || view[4].color == 2) {

          }
          else {
            return {cell:4,color:2}
          }
        }
      }
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && view[i].ant.friend && (view[i].ant.type > view[4].ant.type && view[4].ant.food == 0)) {
          if(match.state.move == 9)
            return {cell:4}
          if(view[i].ant.type == 5)
            return {cell:4}
          var m = findOpenSpace(i,1)
          if(view[m].ant == null)
            return {cell:m}
          return {cell:4,color:2}
        }
      }
    }
    else if(view[4].ant.type <= 4) {
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && !view[i].ant.friend) {
          var canSeeAlly = isAllyAdjacentTo(view,i)
          if(canSeeAlly == 0) {
            if(view[i].color == LOCKDOWN) {
              var a = deRotate(i, 1)
              var b = deRotate(i, -1)
              if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
              if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              if(orthogonals.indexOf(i) >= 0) {
                a = deRotate(i, 2)
                b = deRotate(i, -2)
                if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
                if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              }
            }
            else {
              return {cell:i,color:LOCKDOWN}
            }
            if(view[4].color == LOCKDOWN || view[4].color == COLOR) {
              var ii = deRotate(i,4)
              ii = findOpenSpace(ii,1)
              return {cell:ii}
            }
            return {cell:4,color:COLOR}
          }
          else if(canSeeAlly == 2) {
                var m = deRotate(i, 2)
                j = deRotate(i, -2)
                if(view[m].ant != null && view[i].ant.friend && view[m].ant.type < 5) return {cell:m,color:LOCKDOWN}
                if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return {cell:j,color:LOCKDOWN}
          }
          else if(view[4].color == LOCKDOWN || view[4].color == 2) {

          }
          else {
            return {cell:4,color:2}
          }
        }
      }
    }
    else if(view[4].ant.food > 4) {
        for(var i=0; i < 9; i++) {
            if(view[i].ant != null && !view[i].ant.friend) {
                var canSeeAlly = isAllyAdjacentTo(view,i)
                if(canSeeAlly == 0) {
                    var m = findOpenSpace(i,1)
                    if(view[m].ant == null)
                        return {cell:m,type:1}
                    return {cell:4,color:3}
                }
            }
        }
        var high = getHighestWorker()
        if(high >= 3 && view[4].ant.food % 2 == 1 && view[4].ant.food < 40) {
            var typeToSpawn = 1
            if(view[4].ant.food < 10 && high == 4 && view[4].ant.food % 4 == 1) {
                typeToSpawn = 3
            }
            var m = findOpenSpace(0,1)
            var canSeeAlly = isAllyAdjacentTo(view,m)
            if(canSeeAlly == 0 && view[m].ant == null)
                return {cell:m,type:typeToSpawn}
        }
    }
    //console.log("5")
    var m = match.state.move
    if(isQueen && view[4].ant.food > 0 && view[4].ant.food <= 2 && isAnyColor(COLOR2) == 0 && isAnyColor(COLOR3) == 0 && m < 9) {
        var high = getHighestWorker()+1
        var num = howManyAnts();
        //high += Math.max(num-2,0)
        if(high < 5) {
            m = deRotate(m,match.rot+4) //get space behind
            m = findOpenSpace(m,1) //make sure its open
            if(view[m].ant == null && view[m].food == 0)
                return {cell:m,type:high}
            return {cell:4}
        }
        else {
            //return {cell:9}
            colToPlace = COLOR2
        }
    }
    if(!isQueen && view[4].ant.food > 0 /*&& view[4].ant.type >= 3*/) {
        //console.log("type 3")
        m = match.state.back
        //console.log(m)
        colToPlace = COLOR
    }
    if(view[4].ant.type == 3) {
        colToPlace = COLOR
    }
    //console.log("6")
    if(!matchesColor(view[4].color) && !(!isQueen && view[4].ant.food)) {
        //console.log("6a")
        /*for(var j=0; j < 9; j++) {
            if(j != 4 && view[j].ant != null && view[j].ant.friend && view[j].ant.food > 0 && j != match.back) {
                m = match.state.move
                if(m < 9) {
                    m = findOpenSpace(m,1)
                    if(view[m].ant == null)
                        return {cell:m}
                    return {cell:4}
                }
                return {cell:4,color:colToPlace}
            }
        }*/
        if(isQueen && view[4].color == LOCKDOWN) {
          m = deRotateSide(m,match.rot)
          m = findOpenSpace(m,1)
          return {cell:m}
        }
        return {cell:4,color:colToPlace}
    }
    if(match.fill && !matchesColor(view[4].color)) {
        return {cell:4,color:colToPlace}
    }
    if(m >= 9) {
        if(!matchesColor(view[4].color)) {
            return {cell:4,color:COLOR}
        }
        //console.log("lost! " + view[4].ant.food);
        //console.log(pathLost());
        return pathLost()
    }
    //console.log("7")
    //console.log("m0: " + m + "+" + match.rot)
    m = deRotateSide(m,match.rot)
    //console.log("m1: " + m)
    m = findOpenSpace(m,1)
    //console.log("m2: " + m)
    if(view[4].ant.food > 0 && !matchesColor(view[4].color) /*&& (view[4].ant.type >= 3)*/) {
        var anyFood = false
        for(var x=0;x<9;x++) {
            if(view[x].food > 0) anyFood = true;
        }
        if(!anyFood)
            return {cell:4,color:colToPlace}
    }
    //console.log("m3: " + m)
    m = findOpenSpace(m,1)
    //console.log("m4: " + m)
    if((!isQueen && view[4].ant.food > 0 && view[m].food > 0) && view[m].ant == null) return {cell:4}
    return {cell:m}
}
var ret = getReturn()
ret = sanityCheck(ret)
return ret
function sanityCheck(ret) {
    if(!ret || ret.cell < 0 || ret.cell > 8 || (ret.cell != 4 && (ret.color == null || ret.color == 0) && view[ret.cell].ant != null) || (view[ret.cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) {
        return {cell:4}
    }
    if(ret.type && (view[ret.cell].ant != null || view[ret.cell].food > 0)) {
        return {cell:4}
    }
    return ret;
}

이것은 방대한 양의 개미 기능입니다. 이렇게합니다 :

블랙홀

기능은 정말 간단합니다. 코드 블록의 상단은 matchStates개미가 그들이 향하고있는 방식을 식별하기 위해 사용 하는 객체를 정의하며 , 그렇게함으로써 알려진 탐험 지역 주위를 공전합니다. 그런 다음 몇 가지 도우미 기능 (색상 일치, 개미 계산 등).

bestMatch()개미가 볼 수있는보기 (변경 가능)를 가져와에서 가장 일치하는 것을 찾고 가장 일치하는 것을 matchStates반환합니다.

Queeny는 그녀가 움직일 때 한 가지 일을하고 검은 색을 내립니다.

  • 여왕이 될 노동자를 만들기 위해 갈 때까지 노동자를 만든 다음 파란색으로 바꾸십시오. 근처에 파란색으로 보이는 색상을 배치하는 개미는 모두 파란색으로 표시됩니다.
  • 여왕은 파란색이 보이면 음식을 저장합니다.

타입 1과 2의 노동자들은 음식을 찾을 때까지 여왕처럼 행동하고, 원을 걸어 다니면서 음식을 여왕에게 줄 때까지 색을 버립니다.

유형 3과 4의 근로자는 음식을 찾을 때까지 여왕처럼 행동하고, 여왕에게 음식을 나눠 줄 때까지 원 주위에서 역으로 일합니다 (여전히 색상이 표시됨).

스스로를 잃어버린 개미 pathLost()는 더 똑똑한 직선 알고리즘 인 호출 을 불러냅니다 (문자 그대로 약간의 조정이있는 메타스마트 직선 경로 기능입니다 ).

그 조정은 다음과 같습니다.

  • 유형 1 개미는 무작위로 행동하고 경로를 지우려고 시도합니다 (주로 필요하지 않지만 유형 1 개미는 장기적으로 가치가 없으며 대각선 바둑판을 정리합니다)
  • 비 여왕은 여왕을 볼 수 있다면 행동하지 않을 것입니다
  • 개미가 이전 경로와 만나는 경로의 방향을보고 여전히 결정할 수있을 때마다 해당 경로를 지우고 개미가 다시 경로를 만들도록합니다.

크로스 오버 예

그건 그렇고, 나머지의 대부분은 어떤 개미 (산란 개미, 다른 개미로 이동 음식에 이동 불법 작업을 수행 없다는 것을 보장하기 위해 오류 처리됩니다 에 대한 코드의 가장 큰 오류 처리 덩어리가 바닥에 내려하지만 ... 음식) :

if(view[4].ant.food > 0 && !matchesColor(view[4].color) && (view[4].ant.type >= 3) || surroundingColor > 6) {
  var anyFood = false
  for(var x=0;x<9;x++) {
    if(view[x].food > 0) anyFood = true;
  }
  if(!anyFood)
    return {cell:4,color:colToPlace}
}

거꾸로 걷는 유형 3과 4 개미는 지상에있는 음식 주변에 색이 떨어지지 않습니다 (음식은 경로 방향을 위해 색깔 타일처럼 처리됩니다). 또한 헴된 것으로 생각되는 유형 1 또는 2 개미 (<= 2 무색 공간)는 색이 아래로 내려갑니다. 작은 '섬'의 경우 그들은 영구적으로 갇히기보다는 결국 길을 잃게됩니다.

이 진영에서 얻을 수있는 최대 음식은 게임의 최대 지속 시간 (최소 10k)과 색상 전환 속도에 의해서만 제한됩니다. 더 많은 근로자가 반드시 유익하지는 않지만 몇 명을 일찍 얻는 것이 필수적입니다. 유형 3과 4의 근로자가 가장 효율적이지만 (6 개의 게임 단계마다 여왕에게 6 걸음 더 가까워짐) 너무 일찍 생성하면 총 근로자 수가 줄어 듭니다. 따라서 초기 배치는 큰 영향을 미치지 만 무리에 의해 매핑 된 영역은 보이지 않는 공간이 거의 없어지고 있기 때문에 개미를 데리러 놓기 위해 개미를 잃어 버릴 위험이 없지만 마지막 조각을 모두 잡아 냅니다.

7/23 업데이트

다음과 같은 특정 엣지 케이스에서 몇 가지 문제를 발견했습니다.

여왕은 적에게 이동하고 싶어

그리고 그것을 설명하기 위해 아주 약간의 조정을했습니다. 기본적으로, 적 개미와 적재 된 일꾼을 유색 타일로 취급하십시오.

7/26 업데이트

여우, 난 더 이상 몰라

  • 로스트 옐로우 트레일 오류 처리 기능을 더욱 강력하게 조정
  • 친구 경로 충돌 처리를보다 강력하게 조정했습니다.
  • 트레일 지우개 중화기 코드 추가
  • "파란 흔적"감지 및 처리 코드 추가 [베타]
  • 여왕은 비축 모드에 들어간 후에도 노동자를 계속 생산합니다 (적어도, 적어도)
  • 잘못된 이동 위생
  • 기타 스파게티 코드
  • console.log를 제거했습니다
  • 헤로 브린 제거
  • 추가 디스크 추가

새로운 accretion 디스크

노란 흔적이 없으면 :

노란색 빼기

업데이트 7/26 2 부

  • "파란색으로 무엇을해야합니까?" 암호
    • 제거 디스크 제거
  • 소금과 후추 첨가
  • "어떻게 직면하고 있습니까?"와 관련된 문제가 해결되었습니다. 발각
    • 제거 된 원형
    • 사각형 모양 추가
      • 지루한 것 같아
  • 트레일 지우개에 대한 면역 제거
  • "잃어버린"코드에 스마트를 추가하여 걸린 개미를 줄입니다.

7/31 업데이트

  • 안티 트레일 지우개 코드를 다시 추가했습니다 ( "파란색 제거"업데이트에서 손실 됨)
  • 온전한 검사 기능은 다른 개미에서 세포를 착색 방지
  • 더 나은 지우개 방지 수정 : 더 이상 단일 지우개에 대응하기 위해 3 명의 작업자가 필요하지 않습니다.

8/4 업데이트

약간의 조정.

  • 잠금 색상이 이제 검은 색입니다.
  • 모든 개미는 음식을 배달하기 위해 "거꾸로"걸습니다. 그 역학은 Trail-Eraser가 남긴 "버블"에 갇힌 개미가 더 적을 것입니다
  • 잃어버린 개미가 서로 붙어 붙지 않도록 잘 처리
  • "단독"임계 값을 40으로 줄였습니다.

약점

  • 지워 없앰.
  • 색상 변조.

의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Martin Ender

12

뱀파이어 Mk.8 (Re-Vamped)

누구나 커뮤니티 위키로 바뀌어 다른 피해자를 대상으로 누구나 업데이트 할 수 있습니다. 환경 개념을 사용하여 다양한 타겟팅 코드를 별도로 유지합니다. 변경하려면 새 토너먼트가 평균 점수를 낮추지 않도록 몇 가지 토너먼트를 진행하십시오!


모든 대답은 동일한 하위 수준 도우미 기능 집합을 공유합니다. 이 답변과 관련된 코드를 보려면 "고수준 논리가 여기서 시작됩니다"를 검색하십시오.

// == Shared low-level helpers for all solutions ==
var QUEEN = 5

var WHITE = 1
var COL_MIN = WHITE
var COL_LIM = 9

var CENTRE = 4

var NOP = {cell: CENTRE}

var DIR_FORWARDS = false
var DIR_REVERSE = true
var SIDE_RIGHT = true
var SIDE_LEFT = false

function sanity_check(movement) {
    var me = view[CENTRE].ant
    if(!movement || (movement.cell|0) !== movement.cell || movement.cell < 0 || movement.cell > 8) {
        return false
    }
    if(movement.type) {
        if(movement.color) {
            return false
        }
        if((movement.type|0) !== movement.type || movement.type < 1 || movement.type > 4) {
            return false
        }
        if(view[movement.cell].ant || view[movement.cell].food) {
            return false
        }
        if(me.type !== QUEEN || me.food < 1) {
            return false
        }
        return true
    }
    if(movement.color) {
        if((movement.color|0) !== movement.color || movement.color < COL_MIN || movement.color >= COL_LIM) {
            return false
        }
        if(view[movement.cell].color === movement.color) {
            return false
        }
        return true
    }
    if(view[movement.cell].ant && movement.cell != 4) {
        return false
    }
    if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
        return false
    }
    return true
}

function as_array(o) {
    if(Array.isArray(o)) {
        return o
    }
    return [o]
}

function best_of(movements) {
    var m
    for(var i = 0; i < movements.length; ++ i) {
        if(typeof(movements[i]) === 'function') {
            m = movements[i]()
        } else {
            m = movements[i]
        }
        if(sanity_check(m)) {
            return m
        }
    }
    return null
}

function play_safe(movement) {
    // Avoid disqualification: no-op if moves are invalid
    return best_of(as_array(movement)) || NOP
}

var RAND_SEED = (() => {
    var s = 0
    for(var i = 0; i < 9; ++ i) {
        s += view[i].color * (i + 1)
        s += view[i].ant ? i * i : 0
        s += view[i].food ? i * i * i : 0
    }
    return s % 29
})()

var ROTATIONS = [
    [0, 1, 2, 3, 4, 5, 6, 7, 8],
    [6, 3, 0, 7, 4, 1, 8, 5, 2],
    [8, 7, 6, 5, 4, 3, 2, 1, 0],
    [2, 5, 8, 1, 4, 7, 0, 3, 6],
]

function areAdjacent(A, B) {
    if(A == 4 || B == 4 || A == B) return true
    if(A % 2 == 0 && B % 2 == 0) return false
    if(A % 2 == 1 && B % 2 == 0) return areAdjacent(B,A)
    if(A % 2 == 1 && B % 2 == 1) return !(8-A == B || 8-B == A)
    if(A == 0 && (B == 1 || B == 3)) return true
    if(A == 2 && (B == 1 || B == 5)) return true
    if(A == 6 && (B == 3 || B == 7)) return true
    if(A == 8 && (B == 5 || B == 7)) return true
    return false
}

function try_all(fns, limit, wrapperFn, checkFn) {
    var m
    fns = as_array(fns)
    for(var i = 0; i < fns.length; ++ i) {
        if(typeof(fns[i]) !== 'function') {
            if(checkFn(m = fns[i])) {
                return m
            }
            continue
        }
        for(var j = 0; j < limit; ++ j) {
            if(checkFn(m = wrapperFn(fns[i], j))) {
                return m
            }
        }
    }
    return null
}

function identify_rotation(testFns) {
    // testFns MUST be functions, not constants
    return try_all(
        testFns,
        4,
        (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
        (r) => r
    )
}

function near(a, b) {
    return (
        Math.abs(a % 3 - b % 3) < 2 &&
        Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
    )
}

function try_all_angles(solverFns) {
    return try_all(
        solverFns,
        4,
        (fn, r) => fn(ROTATIONS[r]),
        sanity_check
    )
}

function try_all_cells(solverFns, skipCentre) {
    return try_all(
        solverFns,
        9,
        (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
        sanity_check
    )
}

function try_all_cells_near(p, solverFns) {
    return try_all(
        solverFns,
        9,
        (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
        sanity_check
    )
}

function ant_type_at(i, friend) {
    return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0
}

function friend_at(i) {
    return ant_type_at(i, true)
}

function foe_at(i) {
    return ant_type_at(i, false)
}

function foe_near() {
    for(var i = 0; i < 9; ++ i) {
        if(i !== 4 && view[i].ant && !view[i].ant.friend) {
            return true
        }
    }
    return false
}

function ant_type_near(p, friend) {
    for(var i = 0; i < 9; ++ i) {
        if(i !== 4 && ant_type_at(i, friend) && near(i, p)) {
            return true
        }
    }
    return false
}

function move_agent(agents) {
    var me = view[CENTRE].ant
    var buddies = [0, 0, 0, 0, 0, 0]
    for(var i = 0; i < 9; ++ i) {
        ++ buddies[friend_at(i)]
    }

    for(var i = 0; i < agents.length; i += 2) {
        if(agents[i] === me.type) {
            return agents[i+1](me, buddies)
        }
    }
    return null
}

function grab_nearby_food() {
    return try_all_cells((i) => (view[i].food ? {cell: i} : null), true)
}

function go_anywhere() {
    return try_all_cells((i) => ({cell: i}), true)
}

function colours_excluding(cols) {
    var r = []
    for(var i = COL_MIN; i < COL_LIM; ++ i) {
        if(cols.indexOf(i) === -1) {
            r.push(i)
        }
    }
    return r
}

function generate_band(start, width) {
    var r = []
    for(var i = 0; i < width; ++ i) {
        r.push(start + i)
    }
    return r
}

function colour_band(colours) {
    return {
        contains: function(c) {
            return colours.indexOf(c) !== -1
        },
        next: function(c) {
            return colours[(colours.indexOf(c) + 1) % colours.length]
        },
        prev: function(c) {
            return colours[(colours.indexOf(c) + colours.length - 1) % colours.length]
        }
    }
}

function random_colour_band(colours) {
    return {
        contains: function(c) {
            return colours.indexOf(c) !== -1
        },
        next: function() {
            return colours[RAND_SEED % colours.length]
        }
    }
}

function fast_diagonal(colourBand) {
    var m = try_all_angles([
        // Avoid nearby checked areas
        (rot) => {
            if(
                !colourBand.contains(view[rot[0]].color) &&
                colourBand.contains(view[rot[5]].color) &&
                colourBand.contains(view[rot[7]].color)
            ) {
                return {cell: rot[0]}
            }
        },

        // Go in a straight diagonal line if possible
        (rot) => {
            if(
                !colourBand.contains(view[rot[0]].color) &&
                colourBand.contains(view[rot[8]].color)
            ) {
                return {cell: rot[0]}
            }
        },

        // When in doubt, pick randomly but avoid doubling-back
        (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

        // Double-back when absolutely necessary
        (rot) => ({cell: rot[0]})
    ])

    // Lay a colour track so that we can avoid doubling-back
    // (and mess up our foes as much as possible)
    if(!colourBand.contains(view[CENTRE].color)) {
        var prevCol = m ? view[8-m.cell].color : WHITE

        var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
        for(var i = 0; i < 9; ++ i) {
            ++ colours[view[i].color]
        }

        return {cell: CENTRE, color: colourBand.next(prevCol)}
    }

    return m
}

function checkAllNearEnvirons(colours, buddies) {
        var nearMoves = [victims.length]
        for(var e = 0; e < victims.length; e++) {
                var env = victims[e]
                nearMoves[e] = null
                if(env.near_nest(colours)) {
                        nearMoves[e] = env.near_nest_move(colours, buddies)
                }
        }
        return best_of(nearMoves)
}

function follow_edge(obstacleFn, side) {
    // Since we don't know which direction we came from, this can cause us to get
    // stuck on islands, but the random orientation helps to ensure we don't get
    // stuck forever.

    var order = ((side === SIDE_LEFT)
        ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
        : [0, 1, 2, 5, 8, 7, 6, 3, 0]
    )
    return try_all(
        [obstacleFn],
        order.length - 1,
        (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
        sanity_check
    )
}

function start_dotted_path(colourBand, side, protectedCols) {
    var right = (side === SIDE_RIGHT)
    return try_all_angles([
        (rot) => ((
            !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
            !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
            !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
            !colourBand.contains(view[rot[1]].color)
        )
            ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
            : null)
    ])
}

function lay_dotted_path(colourBand, side, protectedCols) {
    var right = (side === SIDE_RIGHT)
    return try_all_angles([
        (rot) => {
            var ahead = rot[right ? 2 : 0]
            var behind = rot[right ? 8 : 6]
            if(
                colourBand.contains(view[behind].color) &&
                !protectedCols.contains(view[ahead].color) &&
                !colourBand.contains(view[ahead].color) &&
                !colourBand.contains(view[rot[right ? 6 : 8]].color)
            ) {
                return {cell: ahead, color: colourBand.next(view[behind].color)}
            }
        }
    ])
}

function follow_dotted_path(colourBand, side, direction) {
    var forwards = (direction === DIR_REVERSE) ? 7 : 1
    var right = (side === SIDE_RIGHT)

    return try_all_angles([
        // Cell on our side? advance
        (rot) => {
            if(
                colourBand.contains(view[rot[right ? 5 : 3]].color) &&
                // Prevent sticking / trickery
                !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
                !colourBand.contains(view[rot[0]].color) &&
                !colourBand.contains(view[rot[2]].color)
            ) {
                return {cell: rot[forwards]}
            }
        },

        // Cell ahead and behind? advance
        (rot) => {
            var passedCol = view[rot[right ? 8 : 6]].color
            var nextCol = view[rot[right ? 2 : 0]].color
            if(
                colourBand.contains(passedCol) &&
                nextCol === colourBand.next(passedCol) &&

                // Prevent sticking / trickery
                !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
                !colourBand.contains(view[rot[right ? 0 : 2]].color)
            ) {
                return {cell: rot[forwards]}
            }
        }
    ])
}

function escape_dotted_path(colourBand, side, newColourBand) {
    var right = (side === SIDE_RIGHT)
    if(!newColourBand) {
        newColourBand = colourBand
    }

    return try_all_angles([
        // Escape from beside the line
        (rot) => {
            var approachingCol = view[rot[right ? 2 : 0]].color
            if(
                !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
                !colourBand.contains(approachingCol) ||
                colourBand.contains(view[rot[7]].color) ||
                colourBand.contains(view[rot[right ? 6 : 8]].color)
            ) {
                // not oriented, or in a corner
                return null
            }
            return best_of([
                {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
                {cell: rot[right ? 3 : 5]},
                {cell: rot[right ? 0 : 2]},
                {cell: rot[right ? 6 : 8]},
                {cell: rot[right ? 2 : 0]},
                {cell: rot[right ? 8 : 6]},
                {cell: rot[right ? 5 : 3]}
            ])
        },

        // Escape from inside the line
        (rot) => {
            if(
                !colourBand.contains(view[rot[7]].color) ||
                !colourBand.contains(view[rot[1]].color) ||
                colourBand.contains(view[CENTRE].color)
            ) {
                return null
            }
            return best_of([
                {cell: rot[3]},
                {cell: rot[5]},
                {cell: rot[0]},
                {cell: rot[2]},
                {cell: rot[6]},
                {cell: rot[8]}
            ])
        }
    ])
}

function latch_to_dotted_path(colourBand, side) {
    var right = (side === SIDE_RIGHT)

    return try_all_angles([
        (rot) => {
            var approachingCol = view[rot[right ? 2 : 0]].color
            if(
                colourBand.contains(approachingCol) &&
                view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
                !colourBand.contains(view[rot[right ? 5 : 3]].color)
            ) {
                // We're on the wrong side; go inside the line
                return {cell: rot[right ? 5 : 3]}
            }
        },

        // Inside the line? pick a side
        (rot) => {
            var passedCol = view[rot[7]].color
            var approachingCol = view[rot[1]].color
            if(
                !colourBand.contains(passedCol) ||
                !colourBand.contains(approachingCol) ||
                colourBand.contains(view[CENTRE].color)
            ) {
                return null
            }
            if((approachingCol === colourBand.next(passedCol)) === right) {
                return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}])
            } else {
                return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}])
            }
        }
    ])
}


// == High-level logic begins here ==


var TARGET_COLOURS_ZIG = colour_band([4, 5, 7, 8])
var TARGET_COLOURS_FIREFLY = colour_band([2, 5, 8])
var GROUND_COLOURS_BH = colour_band([2, 7, 8])
var SAFE_COLOURS = random_colour_band([8])

var THIEF = 1
var BOUNCER = 2
var LANCE = 4
var LANCE_TIP = 3

var INITIAL_GATHER = 12

function colour_band_prev(band, base) {
    if(!band.contains(base)) {
        return band.next(WHITE)
    }
    var cur = band.next(base)
    var c
    while((c = band.next(cur)) !== base) {
        cur = c
    }
    return cur
}

function white_near(p) {
    for(var i = 0; i < 9; ++ i) {
        if(near(i, p) && view[i].color === WHITE) {
            return true
        }
    }
    return false
}

function white_near(p, min) {
    var c = 0
    for(var i = 0; i < 9; ++ i) {
        if(near(i, p) && view[i].color === WHITE) {
            if(++c >= min) return true
        }
    }
    return false
}

var TARGET_ARRANGEMENT_RAIL = [
    [8,4,5,8,5,2,4,2,6],
    [8,5,2,4,2,6,6,4,5],
    [4,2,6,6,4,5,8,4,5],
    [6,4,5,8,4,5,8,5,2]
]
var TARGET_NEAR_RAIL = [
    [2,4,0,5,8,0,4,8,0,1], //Not Valid for Worker #1
    [2,6,0,4,5,0,4,5,0,0],
    [4,6,0,2,4,0,5,8,0,0],
    [4,8,0,4,6,0,2,4,0,0],
    [4,5,0,5,2,0,2,6,0,1], //NV 1
    [4,5,0,4,5,0,5,2,0,5], //NV Q
    [5,2,0,2,6,0,4,5,0,0],
    [5,8,0,4,8,0,4,6,0,5]  //NV Q
]
var TARGET_COLOURS_RAIL = colour_band([4,5,2,4])
var rail_miners = {
    name:function() { return "rail_miners"; },
    near_nest: function(colours) {
        var bestScore = 0
        var enemyQueen = false
        // check every rotation for each 3x3 rail possibility
        TARGET_NEAR_RAIL.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var sevenVal = 1
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                    score += (arrangement[i] == 0 && view[rot[i]].color == 7)?sevenVal:0
                    score += (arrangement[i] == 0 && !(view[rot[i]].color == 7 || view[rot[i]].color == 1))?-1:0
                    if(arrangement[i] == 0 && view[rot[i]].color == view[rot[i-2]].color) score -= 2
                    if(view[rot[i]].color) sevenVal = 0
                    enemyQueen |= view[i].ant && view[i].ant.type == QUEEN && !view[i].ant.friend
                    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type == THIEF && view[i].color == WHITE) score++
                }
                if(score > bestScore && arrangement[9] != view[4].ant.type) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= (5 - (enemyQueen && view[4].ant.type == 1?1:0))) {
            if(highway.likely_nest(colours)) return false
            return true
        }
        return false
    },
    worth_leeching: function(myFood, buddies) {
        var numFours = 0
        var foodNeed = 11
        for(var i = 0; i < 9; i++) {
            if(foe_at(i) == 4) numFours++
        }
        if(!buddies[THIEF]) return false
        if(view[4].ant.type != 5 && buddies[QUEEN] && myFood < 500 && myFood+buddies[THIEF] > (foodNeed-numFours*3)) return true
        return myFood < 500 && myFood >= (foodNeed-numFours*3)
    },
    near_nest_move: function(colours, buddies) {
        var victim_pos = -1
        var avoid_pos = -1
        var friend_pos = -1
        for(var i = 0; i < 9; i++) {
            if(foe_at(i) == QUEEN) victim_pos = i
            if(foe_at(i) > 0 && foe_at(i) < 4) avoid_pos = i
            if(friend_at(i) == THIEF) friend_pos = i
        }
        if(victim_pos >= 0) return rail_miners.follow_victim(view[4].ant, buddies, colours, victim_pos)
        if(view[4].ant.type == THIEF && buddies[QUEEN]) return NOP
        if(view[4].ant.type == QUEEN && rail_miners.worth_leeching(view[4].ant.food, buddies)) {
            if(avoid_pos >= 0 && view[4].color != WHITE) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[0]} : null),
                        (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[3]} : null)
                    ]),
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[2]} : null),
                        (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[1]} : null)
                    ]),
                    NOP
                ])
            }
            var allowed = [[8,4,8],[4,6,8],[6,8,4],[5,5,6],[6,5,2],[2,6,5]]
            var curr = [view[4].color,view[friend_pos].color,view[8-friend_pos].color]
            var found = false
            allowed.forEach(function (al) {
                if(al[0] == curr[0] && al[1] == curr[1] && al[2] == curr[2]) {
                    found = true
                }
            })
            if(!found) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF && [2,4,5].indexOf(view[rot[2]].color) >= 0 ? {cell: rot[2]} : null),
                        (rot) => (friend_at(rot[1]) === THIEF && [2,4,5].indexOf(view[rot[0]].color) >= 0 ? {cell: rot[0]} : null)
                    ]),
                    NOP
                ])
            }
            return NOP
        }
        return null
    },
    likely_nest: function(colours) {
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        var q = 0
        TARGET_ARRANGEMENT_RAIL.forEach(function (arrangement) {
            var j = 0
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type == THIEF && view[i].color == WHITE) score++
                }
                if(score > bestScore) {
                    bestScore = score
                }
                j++
            })
            q++
        })
        if(view[4].ant.type == THIEF && rail_miners.near_nest(colours)) return true
        if(bestScore >= 7) {
            if(highway.likely_nest(colours)) return false
            return true
        }
        return false
    },

    likely_victim: function(victim_pos) {
        return true
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        if(me.type == QUEEN) {
            if(victim_pos % 2 == 0) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (foe_at(rot[0]) === QUEEN && friend_at(rot[5]) == THIEF ? {cell: rot[2]} : null),
                        (rot) => (foe_at(rot[0]) === QUEEN /*&& friend_at(rot[7]) == THIEF*/ ? {cell: rot[6]} : null)
                    ]),
                    NOP
                ])
            }
            else {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (foe_at(rot[1]) === QUEEN && friend_at(rot[2]) == THIEF ? {cell: rot[5], type: THIEF} : null),
                        (rot) => (foe_at(rot[1]) === QUEEN ? {cell: rot[3], type: THIEF} : null),
                        (rot) => (foe_at(rot[1]) === QUEEN ? {cell: rot[5], type: THIEF} : null),
                        (rot) => (buddies[THIEF] < 4 && foe_at(rot[1]) === QUEEN ? {cell: rot[2], type: THIEF} : null),
                        (rot) => (buddies[THIEF] < 4 && foe_at(rot[1]) === QUEEN ? {cell: rot[0], type: THIEF} : null)
                    ]),
                    NOP
                ])
            }
        }
        return NOP
    },
    find_victim: function(me, buddies, colours) {
        var forwardCell = -1
        var current = view[CENTRE].color
        var target = TARGET_COLOURS_RAIL.next(current)
        var antitarget = TARGET_COLOURS_RAIL.prev(current)
        var queenPos = -1
        for(var i = 0; i < 9; i++) {
            if(i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget && current != WHITE){
                forwardCell = i
            }
            if(friend_at(i) == QUEEN) queenPos = i
        }
        if(forwardCell < 0 && current == 4) {
            target = 4
            antitarget = 2
            for(var i = 0; i < 9; i++) {
                if(i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget){
                    forwardCell = i
                }
            }
        }
        if(me.type == QUEEN) {
            var numEn = 0
            for(var i = 0; i < 9; i++) {
                if(i % 2 == 1 && friend_at(i) == THIEF && friend_at(8-i) == THIEF){
                    if(foe_at(deRotate(i,1)) > 0)
                        return {cell:forwardCell}
                    if(foe_at(deRotate(i,-1)) > 0)
                        return {cell:forwardCell}
                    return NOP
                }
                if(i % 2 == 0 && friend_at(i) == THIEF && friend_at(deRotate(i,2)) == THIEF){
                    return {cell:deRotate(i,3), type:THIEF}
                }
            }
            return wilderness.find_victim(me, buddies, colours)
        }
        else if(forwardCell >= 0) {
            if(friend_at(forwardCell) == QUEEN) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                        (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null)
                    ]),
                    go_anywhere
                ])
            }
        }
        else if(queenPos>=0 && view[queenPos].color == WHITE && (foe_at(deRotate(queenPos,2)) && foe_at(deRotate(queenPos,-2)))) {
            return wilderness.find_victim(me, buddies, colours)
        }
        if(me.type == THIEF && forwardCell >= 0 && buddies[THIEF] == 1) {
            return wilderness.find_victim(me, buddies, colours)
        }
        return NOP
    }
}

var TARGET_ARRANGEMENT_WIND = [
        [5,4,0,7,6,0,6,4,0],
        [7,6,0,6,4,0,5,4,0],
        [6,4,0,5,4,0,7,6,0]
]
var TARGET_ARRANGEMENT_WINDCENTER = [
        [2,7,6,2,6,4,6,5,4],
        [2,6,4,6,5,4,2,7,6],
        [6,5,4,2,7,6,2,6,4]
]
var WIND_BAND = colour_band([5,6,7])
var windmill = {
    name:function() { return "windmill"; },
    near_nest: function(colours) { return false; },
    near_nest_move: function(colours, buddies) { return null; },
    likely_nest: function(colours) { // Main nest detection
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_WIND.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 5 && view[4].ant.type != THIEF) {
            return true
        }

        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_WINDCENTER.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 8) {
            return true
        }
        var buddies = [0, 0, 0, 0, 0, 0]
        for(var i = 0; i < 9; ++ i) {
            ++ buddies[friend_at(i)]
        }
        return buddies[LANCE] || buddies[LANCE_TIP]
    },
    worth_leeching: function(myFood, buddies) {
        if(view[4].ant.type == THIEF && (buddies[LANCE] > 0 || buddies[LANCE_TIP] > 0)) return true
        return myFood > 5 || (myFood > 1 && buddies[LANCE])
    },
    likely_victim: function(victim_pos) {
        return false
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        // nest is chaotic and varies by direction of approach
        // We'll let the Find Victim logic handle this
        return NOP
    },

    find_victim: function(me, buddies, colours) {
        if(me.type == THIEF) {
            var queenPos = -1
            var lancePos = -1
            var tipPos = -1
            for(var i=0;i<9;i++) {
                if(friend_at(i) == QUEEN) queenPos = i
                if(friend_at(i) == LANCE) lancePos = i
                if(friend_at(i) == LANCE_TIP) tipPos = i
            }
            if(queenPos < 0 || (foe_at(deRotate(queenPos,1)) > 0 && foe_at(deRotate(queenPos,2)) > 0)) {
                if(queenPos < 0)
                    return go_anywhere
                return {cell:8-queenPos}
            }
            if(queenPos % 2 == 1 && tipPos % 2 == 0) {
                return go_anywhere
            }
            if(queenPos % 2 == 0 && lancePos % 2 == 1) {
                return go_anywhere
            }
            if(queenPos % 2 == 1 && foe_at(deRotate(queenPos,-2)) > 0) {
                return go_anywhere
            }
            return NOP
        }
        if(buddies[LANCE_TIP]) {
            var lancePos = -1
            for(var i=0;i<9;i++) {
                if(friend_at(i) == LANCE_TIP) {
                    lancePos = i
                }
            }
            if(buddies[LANCE]) {
                if(friend_at(8-lancePos) == LANCE) {
                    if(foe_at(deRotate(8-lancePos,1)) == 1 || foe_at(deRotate(8-lancePos,2)) == 1) {
                        var ret = NOP
                        if(lancePos % 2 == 1)
                            ret = {cell:deRotate(8-lancePos,-2)}
                        if(lancePos % 2 == 0)
                            ret = {cell:deRotate(8-lancePos,-3)}
                        if(!sanity_check(ret)) {
                            ret = best_of([
                                try_all_cells_near(lancePos, (i) => (ant_type_at(i) == 0 && view[i].color == 6 ? {cell: i} : null), true),
                                NOP
                            ])
                        }
                        return ret
                    }
                    if(foe_at(deRotate(lancePos,-2)) > 0) {
                        return {cell:deRotate(lancePos,2)}
                    }
                    return NOP
                }
                if(friend_at(deRotate(lancePos,3)) == LANCE) {
                    if((view[lancePos].color == 2 && view[4].color == 7) || foe_at(8-lancePos)) {
                        return {cell:deRotate(lancePos,1)}
                    }
                    return NOP
                }
                if(view[4].color == 6 && view[lancePos].color == 6 && friend_at(deRotate(lancePos,1)) == LANCE) {
                    if(foe_at(deRotate(lancePos,2)) > 0) {

                        return {cell:8-deRotate(lancePos,2)}
                    }
                    return NOP
                }
                if(view[lancePos].color == 2 && view[deRotate(lancePos,-3)].color == 5 && friend_at(deRotate(lancePos,-3)) == LANCE) {
                    return NOP
                }
                if(lancePos % 2 == 0) {
                    if(foe_at(deRotate(lancePos,-1)) > 0 && lancePos % 2 == 1) return {cell:deRotate(lancePos,2)}
                    if(view[deRotate(lancePos,-1)].color != 5) return {cell:deRotate(lancePos,-1),color:5}
                    if(view[deRotate(lancePos,-1)].color == 3 && view[4].color == 1) return {cell:4,color:3}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 3) return {cell:4,color:2}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 2) return {cell:4,color:1}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 7 && view[deRotate(lancePos,-1)].ant == null) return {cell:deRotate(lancePos,-1),type:THIEF}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 7) return {cell:4,color:3}
                }
                return {cell:deRotate(lancePos,-1)}
            }
            if(view[4].color == WHITE && view[lancePos].color == WHITE) {
                return {cell:deRotate(lancePos,-2),type:BOUNCER}
            }
            if(view[deRotate(lancePos,-1)].ant != null && view[deRotate(lancePos,-1)].ant.type == 5) {
                return {cell:deRotate(lancePos,2)}
            }
            if(view[4].color == 6 && view[deRotate(lancePos,1)].color == 7) {
                return {cell:deRotate(lancePos,1)}
            }
            if(foe_at(deRotate(lancePos,-2)) > 0 || foe_at(deRotate(lancePos,-3)) > 0) {
                if(foe_at(deRotate(lancePos,-2)) > 0 && foe_at(deRotate(lancePos,3)) > 0 && (foe_at(deRotate(lancePos,-1)) > 0 || foe_at(deRotate(lancePos,4)) > 0)) {
                    return {cell:deRotate(lancePos,1)}
                }
                if(foe_at(deRotate(lancePos,3)) > 0) {
                    return NOP
                }
                return {cell:deRotate(lancePos,1)}
            }
            if(foe_at(deRotate(lancePos,2)) > 0 && view[deRotate(lancePos,-1)].color != 2) {
                return {cell:deRotate(lancePos,-1),color:2}
            }
            if(foe_at(deRotate(lancePos,-1)) > 0) {
                return {cell:deRotate(lancePos,1)}
            }
            if(lancePos % 2 == 1 && friend_at(deRotate(lancePos,-1)) == THIEF) {
                return {cell:deRotate(lancePos,-2)}
            }
            return {cell:deRotate(lancePos,-1)}
        }
        else if(buddies[LANCE]) {
            var lancePos = -1
            for(var i=0;i<9;i++) {
                if(view[i].ant && view[i].ant.friend && view[i].ant.type == LANCE) {
                    lancePos = i
                }
            }
            if(view[4].color == 3 && lancePos % 2 == 1) return NOP
            var moveNext = lancePos % 2 == 1 ? {cell:deRotate(lancePos,2)} : {cell:deRotate(lancePos,1)}
            if(view[moveNext.cell].ant != null && !view[moveNext.cell].ant.friend) {
                moveNext = {cell:deRotate(lancePos,1),type:LANCE_TIP}
            }
            if(view[lancePos].ant.food > 0) {
                if(lancePos % 2 == 1)
                    return {cell:deRotate(lancePos,4),type:LANCE_TIP}
                else
                    return {cell:deRotate(lancePos,3),type:LANCE_TIP}
            }
            if(view[lancePos].color == 6 && view[moveNext.cell].color == 8 && view[deRotate(lancePos,2)].color == 5) {
                return {cell:moveNext.cell,type:LANCE_TIP}
            }

            return moveNext
        }
        else {
            var current = view[CENTRE].color
            var standOn = WIND_BAND.next(WIND_BAND.next(WIND_BAND.next(current)))
            var target = WIND_BAND.next(current)
            var antitarget = WIND_BAND.next(target)
            if(current != standOn) return wilderness.find_victim(me, buddies, colours)

            var ret = best_of([
                try_all_cells((i) => ((i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget && ([2,5,6].indexOf(view[deRotate(i,-1)].color) >= 0) && (view[i].color != 5 || view[deRotate(i,1)].color == 4)) ? {cell: i, type: LANCE} : null), true),
                NOP
            ])
            if(ret.cell == 4) {
                return wilderness.find_victim(me, buddies, colours)
            }
            return ret
        }
        return NOP
    }
}

var TARGET_ARRANGEMENT_HIGHWAY = [
    [2,3,7,6,8,2,3,7,6],
    [2,3,7,7,6,4,4,2,3],
    [2,4,6,7,3,2,4,6,7],
    [3,2,4,4,6,7,7,3,2],
    [3,4,7,7,2,6,6,3,4],
    [3,4,7,2,6,3,4,7,2],
    [3,6,2,2,7,4,4,3,6],
    [4,7,2,2,5,6,3,4,7],
    [4,6,7,2,6,3,3,4,7],
    [4,6,7,7,3,2,2,4,6],
    [6,4,2,3,7,6,4,2,3],
    [7,3,2,2,4,6,6,7,3],
    [7,4,3,6,2,7,4,3,5]
]
var HIGHWAY_BAND = colour_band([2,7,4,3,6])
var HIGHWAY_BAND2 = colour_band([2,3,7,6,4])

var highway = {
    name:function() { return "highway"; },                                     // For debugging
    near_nest: function(colours) { return false; },                // For dodging enemy workers without getting lost
    near_nest_move: function(colours, buddies) { return null; }, // How to move when near_nest is true
    likely_nest: function(colours) { // Main nest detection
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_HIGHWAY.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 7) {
            return true
        }
        if(this.isCenter(colours)) return true

        return false
    },         // Main nest detection
    isCenter: function(colours) {
        var bestScore = 0
        ROTATIONS.forEach(function (rot){
            var score = 0
            for(var i = 0; i < 9; i++) {
                if(i >= 3 && i <= 5 && [2,7,4,3,6].indexOf(view[rot[i]].color) >= 0 && (i == 4 || view[rot[i]].color != view[rot[8-i]].color)) {
                    if(i != 4) {
                        score++
                    }
                    else {
                        if(view[rot[3]].color != view[rot[5]].color && view[rot[1]].color == view[rot[7]].color && (view[rot[4]].color != view[rot[1]].color && view[rot[4]].color != view[rot[3]].color && view[rot[4]].color != view[rot[5]].color && view[rot[4]].color != view[rot[7]].color)) {
                            score++
                        }
                    }
                }
                else if(i >= 6) {
                    if(view[rot[i]].color == view[rot[i-6]].color && [2,7,4,3,6].indexOf(view[rot[i]].color) >= 0 && (i == 7 || view[rot[i]].color != view[rot[8-i]].color) && view[rot[i]].color != view[4].color) {
                        score += 2
                    }
                }
            }
            if(score > bestScore) {
                bestScore = score
            }
        })
        if(bestScore >= 7) {
            return true
        }
        return false
    },
    worth_leeching:function(myFood, buddies){ return myFood > 80 && myFood < 500; }, // Is this nest worth leeching?
    likely_victim: function(victim_pos) {
        return true
    },   // Identifying the target queen
    follow_victim: function(me, buddies, colours, victim_pos) {
        if(me.type == QUEEN && buddies[THIEF] < 3) {
            return best_of([
                try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true),
                try_all_cells((i) => ({cell: i, type: THIEF}), true)
            ])
        }
        if(me.type == THIEF && buddies[QUEEN])
            return NOP
        return go_anywhere
    },   // How to handle what happens when the enemy queen is found
    find_victim: function(me, buddies, colours) {
        if(me.type == THIEF && !buddies[QUEEN]) {
            for(var i=0;i<9;i++) {
                if(foe_at(i)) return NOP
            }
            var target = HIGHWAY_BAND.prev(view[4].color)
            var followRail = best_of([
                try_all_cells((i) => (i % 2 == 1 && view[i].color == target) ? {cell:i} : null),
                NOP
            ])
        }
        else {
            var target = HIGHWAY_BAND.next(view[4].color)
            var followRail = best_of([
                try_all_cells((i) => (i % 2 == 1 && view[i].color == target) ? {cell:i} : null),
                NOP
            ])
        }
        return followRail
    }                // How to follow the nest
}

var wilderness = {
    name:function() { return "wilderness"; },
    near_nest: function(colours) { return false; },
    near_nest_move: function(colours, buddies) { return null; },
    likely_nest: function(colours) {
        return true
    },
    worth_leeching: function(myFood, buddies) {
        return true
    },
    likely_victim: function(victim_pos) {
        return true
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        // We stumbled across a random queen; make the most of it
        // TODO
        if(rail_miners.near_nest(colours)) {
            return rail_miners.follow_victim(me, buddies, colours, victim_pos)
        }

        // avoids blocking off the rail miner queen from her workers
        // (we'd like to leech her again)
        if(me.type === QUEEN && !buddies[THIEF] && me.food > 0) {

            // Make a buddy to help us steal
            return best_of([
                try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true),
                try_all_cells((i) => ({cell: i, type: THIEF}), true)
            ])
        }
        else if(me.type === QUEEN){
            var enemyCount = 0
            var allyPos = -1
            for(var a=0; a<9; a++) {
                if(a != 4 && view[a].ant != null) {
                    if(view[a].ant.friend) {
                        if(near(a,victim_pos)){
                            allyPos = a
                        }
                    }
                    else if(view[a].ant.type != 5) {
                        enemyCount++
                    }
                }
            }
            if(enemyCount >= buddies[THIEF] && allyPos >= 0) {
                //if next to the queen and we're outnumbered, move back to the center of the rail.
                var target = TARGET_COLOURS_RAIL.prev(view[allyPos].color)
                var best = best_of([
                    try_all_cells((i) => (near(i, victim_pos) && i % 2 == 0 ? {cell: i, type: THIEF} : null), true),
                    try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true)
                ])
                if(best != null) return best

                best_of([
                    try_all_cells((i) => ((view[i].color == target && i != 4 && areAdjacent(i,a)) ? {cell: i} : null))
                ])
                if(best != null) return best

                return best_of([
                    {cell:deRotate(allyPos,1)},
                    {cell:deRotate(allyPos,-1)}
                ])
            }
        }

        return NOP
    },
    find_victim: function(me, buddies, colours) {
        if(me.type === QUEEN) {
            var in_void = true
            for(var i = 0; i < 9; ++ i) {
                if(view[i].color !== WHITE && !SAFE_COLOURS.contains(view[i].color)) {
                    in_void = false
                    break
                }
            }
            if(!in_void) {
                // because of avoiding returning Miner on a Rail workers
                // we dodge sideways and this takes us back onto track
                var nearMove = checkAllNearEnvirons(colours, buddies)
                if(nearMove) return nearMove
            }
            return best_of([
                // Make a buddy once we have a reasonable stash of food so we can
                // search the board faster
                // (but avoid making buddies when there's a potential nest nearby
                // better to wait until we find their queen)
                (!buddies[THIEF] && me.food >= INITIAL_GATHER && in_void) &&
                    try_all_cells((i) => ({cell: i, type: THIEF}), true),

                // Follow buddy in search of victims
                buddies[THIEF] && try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[2]} : null),
                    (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[1]} : null)
                ]),
                buddies[THIEF] && try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[3]} : null)
                ]),
                buddies[THIEF] && NOP, // Don't lose our buddy!

                // Random walk until we can make a buddy or find the victim
                grab_nearby_food,
                foe_near() ? go_anywhere : fast_diagonal.bind(null, SAFE_COLOURS),
                go_anywhere
            ])
        } else if(me.type === THIEF) {
            return best_of([
                // Lost the queen! Random walk because we have nothing better to do.
                // (don't leave lines; they could disrupt the pattern)
                !buddies[QUEEN] && go_anywhere,
                buddies[BOUNCER] && go_anywhere,
                buddies[THIEF] > 1 && go_anywhere, //untested
                // Follow queen in search of victims
                try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null)
                ]),
                NOP // Don't lose our buddy!
            ])
        }
    }
}

var victims = [highway, rail_miners, windmill]

function guess_environment(colours, buddies) {
    var food = view[4].ant.food
    if(view[4].ant.type !== QUEEN) {
        for(var i = 0; i < 9; i++) {
            if(i != 4 && view[i].ant && view[i].ant.friend && view[i].ant.type === QUEEN) {
                food = view[i].ant.food
            }
        }
    }
    for(var i = 0; i < victims.length; ++ i) {
        if(victims[i].likely_nest(colours) && victims[i].worth_leeching(food, buddies)) {
            return victims[i]
        }
    }

    return wilderness
}

function is_safe(i) {
    var nearThief = false
    var nearOfficer = false
    for(var j = 0; j < 9; ++ j) {
        if(friend_at(j) === THIEF) {
            nearThief = true
        }
        if(foe_at(j) && foe_at(j) !== QUEEN) {
            nearOfficer = true
        }
    }
    return nearThief && !nearOfficer
}

function move(me, buddies) {
    var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    for(var i = 0; i < 9; ++ i) {
        ++ colours[view[i].color]
    }
    var env = guess_environment(colours,buddies)
    var victim_pos = -1
    var queen_pos = -1
    for(var i = 0; i < 9; ++ i) {
        if(foe_at(i) === QUEEN && env.likely_victim(i) && view[i].ant.food > 0) {
            victim_pos = i
            if(view[i].ant.food > 0) {
                break
            }
        }
        if(friend_at(i) === QUEEN) {
            queen_pos = i
        }
    }

    var in_void = true
    for(var i = 0; i < 9; ++ i) {
        if(view[i].color !== WHITE || (i != 4 && me.type === BOUNCER && friend_at(i) === BOUNCER)) {
            in_void = false
            break
        }
    }
    if(me.type === BOUNCER) {
        if(env === wilderness && in_void) {
            // Our work is done; leave queen and wander at random
            if(buddies[QUEEN]) {
                return best_of([
                    try_all_cells((i) => (ant_type_near(i, true) ? null : {cell: i}), true),
                    go_anywhere
                ])
            }
            return NOP
        }
        else if(env === rail_miners) {
            // Our work is done; leave queen and wander at random
            if(buddies[QUEEN]) {
                var allAngles = try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null),
                    NOP
                ])
                return best_of([
                    //if next to an enemy queen, move out of the way
                    try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:9-i} : null), true),
                    try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:7-i} : null), true),
                    allAngles
                ])
            }
            return NOP
        } else if(buddies[QUEEN]) {
            // Escort queen out of nest
            var allAngles = try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null),
                NOP
            ])

            return best_of([
                //if next to an enemy queen, move out of the way
                try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:9-i} : null), true),
                try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:7-i} : null), true),
                allAngles
            ])
        }
        else {
            return go_anywhere
        }
    } else if(buddies[BOUNCER]) {
        if(me.type === QUEEN) {
            // Be escorted out of nest
            return try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === BOUNCER ? {cell: rot[2]} : null),
                (rot) => (friend_at(rot[0]) === BOUNCER ? {cell: rot[1]} : null),
                go_anywhere,
                NOP
            ])
        } else {
            // Get out of the way
            return try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[7]} : null),
                (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[8]} : null),
                (rot) => (friend_at(rot[1]) === BOUNCER ? {cell: rot[7]} : null),
                (rot) => (friend_at(rot[0]) === BOUNCER ? {cell: rot[8]} : null),
                go_anywhere
            ])
        }
    }
    if(victim_pos !== -1) {
        // abandon the queen if she's dry.
        // abandon rail miner's queen so she has at least 10 food (otherwise she produces workers 3:4 food she aquires)
        // value is higher than 10 because there's two to three rounds of theft (at 4 ants each) before the queen gets out of range
        // this can still leave the rail miner's queen lower than 10, but unlikely
        // other queens are abandoned if they have less than 5 food, due to the "max 4 ants stealing" and at 0 food, she's not a target.
        if(view[victim_pos].ant.food < 5 || (env == rail_miners && view[victim_pos].ant.food < 28)) {
            if(me.type == THIEF) {
                if(rail_miners.near_nest(colours)) {
                    // we'd rather reuse the workers
                    return NOP
                }
            }
            // Victim is out of food; bounce out of nest
            if(env == rail_miners) {
                if(me.type == QUEEN && me.food < 300 && !buddies[BOUNCER]) {
                    if(friend_at(deRotate(victim_pos,2)) == THIEF && foe_at(deRotate(victim_pos,3)) == 0) return {cell:deRotate(victim_pos,3),type:BOUNCER}
                    if(friend_at(deRotate(victim_pos,-2)) == THIEF && foe_at(deRotate(victim_pos,-3)) == 0) return {cell:deRotate(victim_pos,-3),type:BOUNCER}
                }
                // murder SlM
                return NOP
            }
            var m = try_all_cells((i) => ({cell: i, type: BOUNCER}), true)
            if(m) {
                return m
            }
        }
        if(me.type === QUEEN && buddies[THIEF] && !is_safe(CENTRE)) {
            // Try to avoid getting food stolen back from us
            var m = try_all_cells((i) => (is_safe(i) ? {cell: i} : null), true)
            if(m) {
                return m
            }
        }
        return env.follow_victim(me, buddies, colours, victim_pos)
    } else {
        return env.find_victim(me, buddies, colours)
    }
}

// LANCE is only used by windmill targetting, easier to break this out as its own method
function moveLance(me, buddies) {
    var queenPos = -1
    var tipPos = -1
    var enQueenPos = -1
    if(buddies[BOUNCER]) {
        for(var i=0;i<9;i++) {
            if(friend_at(i) == BOUNCER) {
                return {cell:8-i}
            }
        }
    }
    for(var i=0;i<9;i++) {
        if(friend_at(i) == QUEEN) {
            queenPos = i
        }
        if(friend_at(i) == LANCE_TIP) {
            tipPos = i
        }
        if(foe_at(i) == QUEEN) enQueenPos = i
    }
    if(!buddies[QUEEN]) {
        for(var i=0;i<9;i++) {
            if(i % 2 == 0 && friend_at(i) == QUEEN) {
                if(view[deRotate(i,3)].ant != null && view[deRotate(i,3)].ant.friend && view[deRotate(i,3)].ant.type == LANCE_TIP) return NOP
                return {cell:deRotate(i,1)}
            }
        }
        if(!buddies[LANCE_TIP] && !buddies[THIEF] && view[4].color == 2) {
            for(var i = 0; i < 9; ++ i) {
                if(view[i].color == 1) return {cell:i}
            }
        }
        if(enQueenPos >= 0 && enQueenPos % 2 == 0 && foe_at(deRotate(enQueenPos,1)) == 1) {
            return {cell:deRotate(enQueenPos,-3)}
        }
        if(enQueenPos >= 0 && enQueenPos % 2 == 1 && foe_at(deRotate(enQueenPos,2)) == 1) {
            return {cell:8-enQueenPos}
        }
        if(enQueenPos >= 0 && (me.food > 0 || foe_at(deRotate(enQueenPos,-1)) || foe_at(deRotate(enQueenPos,3)))) {
            if(enQueenPos % 2 == 0 && (foe_at(deRotate(enQueenPos,4)) || friend_at(deRotate(enQueenPos,4)) == THIEF)) {
                return {cell:deRotate(enQueenPos,-3)}
            }
        }
        return NOP
    }
    if(buddies[LANCE_TIP]) {
        if(deRotate(queenPos,-1) == tipPos && view[tipPos].color == 8) return {cell:8-tipPos}
        if(deRotate(queenPos,-1) == tipPos) return try_all_cells((i) => (areAdjacent(i,tipPos) && view[i].color == 5 ? {cell:i} : null))
        if(foe_at(8-tipPos) == QUEEN) return {cell:8-tipPos,color:6}
        if(foe_at(8-queenPos) > 0 || foe_at(deRotate(8-queenPos,1)) > 0) return NOP
        return try_all_cells((i) => (!areAdjacent(i,queenPos) && !areAdjacent(i,tipPos) ? {cell:i} : null))
    }
    if(view[4].color != 4 && view[4].color != 6) {
        if(foe_at(8-queenPos) == QUEEN) {
            var formation = try_all_angles.bind(null, [
                (rot) => (foe_at(rot[1]) === 1 && foe_at(rot[2]) === QUEEN ? {cell: rot[3]} : null),
                (rot) => (foe_at(rot[1]) === 1 && foe_at(rot[0]) === QUEEN ? {cell: rot[7]} : null),
                (rot) => (foe_at(rot[1]) === 1 && view[rot[1]].ant.food > 0 && foe_at(rot[6]) === QUEEN && friend_at(rot[2]) === QUEEN ? {cell: rot[5]} : null),
            ])()
            if(formation != null) {
                return formation
            }
            return NOP
        }
        if(foe_at(deRotate(queenPos,1)) > 0 && foe_at(deRotate(queenPos,-1)) > 0) {
            return {cell:deRotate(queenPos,-3)}
        }
        return best_of([
            try_all_cells((i) => (enQueenPos ==-1 && i % 2 == 1 && (view[i].color == 4 || view[i].color == 6) && view[deRotate(i,1)].color != 2 && view[deRotate(i,-1)].color != 2 && areAdjacent(i,queenPos) ? {cell: i} : null), true),
            ((view[4].color != 6 || view[4].color != 4) && queenPos % 2 == 0 && view[deRotate(queenPos,-3)].color == 5) ? {cell:4,color:6} : null,
            NOP
        ])
    }
    else {
        var queenOn = view[8-queenPos].color
        var target = WIND_BAND.next(queenOn)
        var prior = WIND_BAND.next(target)
        var followRail = best_of([
            try_all_cells((i) => (view[deRotate(i,-3)].color == prior && view[deRotate(i,-1)].color == target && areAdjacent(i,queenPos) && (view[i].color == 4 || view[i].color == 6) ? {cell: i} : null), true),
            queenPos % 2 == 1 ? (view[queenPos].color == 4 || view[4].color == 4 ? NOP : {cell:deRotate(queenPos,-2)}) : (view[queenPos].color == 4 || view[queenPos].color == 6 ? {cell:deRotate(queenPos,-1)} : NOP)
        ])

        if(view[deRotate(queenPos,-1)].ant != null) {
            if(!view[deRotate(queenPos,-1)].ant.friend && view[deRotate(queenPos,-2)].ant != null && !view[deRotate(queenPos,-2)].ant.friend) {
                return NOP
            }
            if(queenPos % 2 == 0 && !view[deRotate(queenPos,-1)].ant.friend && view[deRotate(queenPos,-2)].ant == null && (view[queenPos].color == 3 || view[queenPos].color == WHITE)) {
                return {cell:deRotate(queenPos,-3)}
            }
            if(queenPos % 2 == 0 && friend_at(deRotate(queenPos,-1)) == THIEF && view[deRotate(queenPos,-2)].ant == null && (view[queenPos].color == 3 || view[queenPos].color == WHITE)) {
                return {cell:deRotate(queenPos,-3)}
            }
            return NOP
        }
        if(me.food > 0 && queenPos % 2 == 0) {
            return {cell:deRotate(queenPos,-1)}
        }
        if(foe_at(deRotate(queenPos,-3)) > 0 && (view[queenPos].color == 1 || view[deRotate(queenPos,1)].color == 1 || view[deRotate(queenPos,-1)].color == 1)) {
            if(view[queenPos].color == 3) {
                return followRail
            }
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if((foe_at(deRotate(queenPos,-2)) > 0 || foe_at(deRotate(queenPos,-3)) > 0) && queenPos % 2 == 0 && view[deRotate(queenPos,-1)].color == 5) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if(view[deRotate(queenPos,-4)].ant != null && !view[deRotate(queenPos,-4)].ant.friend && (view[queenPos].color == 1 || view[deRotate(queenPos,1)].color == 1 || view[deRotate(queenPos,-1)].color == 1)) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if((followRail == null || followRail.cell == 4) && foe_at(deRotate(queenPos,-2)) == 1) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if(followRail != null && followRail.cell != 4 && view[followRail.cell].color == 6 && view[deRotate(followRail.cell,1)].color == 6) {
            followRail = {cell:deRotate(followRail.cell,1)}
        }
        return followRail
    }
    return NOP
}

// LANCE_TIP never needs to move
// Unfortunately, reusing an existing worker type for this purpose is not easily possible.
// Used against Sliding Miners as a stationary blocker to prevent the queen slipping past.
function moveTip(me, buddies) {
    var queenPos = -1
    var in_void = true
    for(var i=0;i<9;i++) {
        if(friend_at(i) == QUEEN) {
            queenPos = i
        }
        if(view[i].color != WHITE) {
            in_void = false
        }
    }
    var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    var enemies = 0
    for(var i = 0; i < 9; ++ i) {
        ++ colours[view[i].color]
        if(foe_at(i) > 0) enemies++
    }
    var onRails = rail_miners.near_nest(colours)
    if(buddies[QUEEN] && !buddies[LANCE]) {
        if(onRails) return NOP
        if(foe_at(8-queenPos) == 4) {
            return {cell:deRotate(queenPos,2)}
        }
        if(in_void) return {cell:deRotate(queenPos,4)}
        if(enemies == 2 && queenPos % 2 == 0 && view[deRotate(queenPos,1)].ant == null) {
            return {cell:queenPos,color:7}
        }
        if(enemies == 2 && queenPos % 2 == 1) {
            return {cell:deRotate(queenPos,-1),color:7}
        }
    }
    if(buddies[QUEEN] && buddies[LANCE]) {
        if(enemies == 0 && view[queenPos].color == 1) return NOP
        if(view[deRotate(queenPos,1)].color == 5 && friend_at(deRotate(queenPos,1)) == LANCE) return {cell:deRotate(queenPos,4)}
        return {cell:deRotate(queenPos,2)}
    }
    if(!buddies[QUEEN] && view[4].color == 2) {
        for(var i = 0; i < 9; ++ i) {
            if(view[i].color == 8) return {cell:i}
        }
    }
    if(queenPos >=0 && foe_at(deRotate(queenPos,2)) > 0 && view[deRotate(queenPos,2)].ant.food == 0 && foe_at(deRotate(queenPos,4)) > 0 && view[deRotate(queenPos,4)].ant.food > 0) {
        return {cell:queenPos,color:7}
    }
    return NOP
}

function deRotate(m, amt) {
    var rotationsCW = [1,2,5,8,7,6,3,0]
    var rotationsCCW = [3,6,7,8,5,2,1,0]
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8]
    amt = -amt
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8]
}

return play_safe(move_agent([
    THIEF, move,
    QUEEN, move,
    BOUNCER, move,
    LANCE, moveLance,
    LANCE_TIP, moveTip
]))

"적의 여왕에 인접한 무적의 노동자가 존재한다면 1 조각의 음식을 훔칠 것"이라는 규칙을 악용 한 답변을 게시 한 사람은 아무도 없었습니다.

이 뱀파이어는 거머리에서 벗어나기 위해 특정 목표를 찾고 있으며, 이것은 지속적으로 업데이트되며 (이것은 커뮤니티 위키이기 때문에 worth_leeching) 더 이상 수익성이 떨어지면 기능을 통해 비활성화 됩니다.

점을 유의 worth_leeching기능 (false를 반환하는 경우) 목표를 비활성화에서의 사용뿐만 아니라, 언급, 예를 들면 가능성이 트랩을 쫓고에서 뱀파이어를 방지 의사 결정을 극대화하기 위해 주어진 대상 객체를 제어 할 수 있습니다 (지구라트이없는이 작은 주머니를 만들어 뱀파이어가 충분한 양의 음식을 모을 때까지 갇 히면 라운드를 완전히 낭비하지 않습니다 (즉, 12 음식 만). 전달 된 매개 변수는 view개체 를 쿼리하지 않고도 메서드를 매우 유연하게 만듭니다.

대상에 대한 설명은 코드에 표시된 순서대로 따릅니다.

블랙홀 (타겟 비활성화)

이것이 블랙홀을 발견했을 때, 우리가 여왕을 찾게 될지, 노동자들이 우리 음식을 배수 할 것인지, 아니면 튀어 나와서 계속 검색 할 것인지는 무작위입니다. 블랙홀은 타겟팅하기가 매우 어렵다는 것이 밝혀졌습니다.

Ziggurat (타겟 비활성화)

지구라트의 중심에 도착하면 여왕은 도둑을 만들어 가능한 많은 음식을 최대한 빨리 추출합니다. 식민지가 노동자 군대를 낳아 (우리 자신의 음식을 낭비) 우리를 대항하기 때문에 금식해야합니다. 모든 음식이 사라지면, 우리는 "바운서"를 만들어 다음 희생자를 찾아 나선다.

블랙홀의 경우, 이것은 표면에 앉아있는 작업자를 사용하여 대상 여왕이 지나갈 때까지 기다리는 반면, 여왕은 깊숙히 앉아 지나가는 노동자가 그녀를 낯설지 않게합니다. 표적 여왕이 결국 지나갈 때, 우리는 가능한 한 많이 따라갑니다.

레일에있는 광부의 경우, 여왕이 광부의 메인 레일 시스템 중앙에 앉아 있는지 확인하기 위해 무차별 대입 검색을 사용합니다. 그런 다음 그것을 소스로 되돌립니다 (광부의 노동자들이 물러 나게합니다). 여왕에 도착하면 정상적으로 도둑을 낳고 여왕을 9 개의 음식으로 배출합니다. 식량 10 개 미만에서 광부 여왕은 자신이 제공 한 4 가지 식량마다 3 명의 근로자를 생성하여 낮은 수익률 전망을 고수합니다. 튀어 나와 나중에 돌아옵니다. (이 환경 코드를 제공 한 Draco18s에게 감사드립니다!)

이것이 Ziggurat를 발견하면, 초기 프로토 타입에서 볼 수 있듯이, 꽤 잘 작동하며 흥미로운 폭발을 일으 킵니다 (수신이 추가되기 전) :

폭발 지그 구트

FireFly (대상 비활성화)

Firefly를 타겟팅하는 블록은 Ziggurat 코드를 기준으로 사용하지만 사용 된 색상을 무시합니다. 이를 통해 모든 작성자가 바이트 수를 줄이면서 새로운 뱀파이어 대상을 쉽게 만들 수 있습니다. Firefly가 음식을 수집하지 않았지만 Mk에서 다시 활성화했을 때 Firefly 코드가 비활성화되었습니다. 5.

FIrefly와 관련이 없지만 Mk.4는 대상의 작업자 (레일 방지 광부 코드에서 사용)의 측면 스테핑을 처리하기 위해 일부 추가 객체 메소드에 추가하여 뱀파이어 여왕이 작업 레일 광부 수리공을 안전하게 만날 수있게합니다. 두 개미가 영구적으로 붙어있는

철도 광부 (MoaR) / 슬라이딩 마인더 (SlM)

철도에서 광부를 찾으면 음식이 도난 당하지 않도록 철도를 출국 방향 (무선철 근로자가 움직이는 방향과 동일)으로 추적합니다. 레일의 끝을 찾으면 레일 자체 작업자 4 (수리공)의 광부 역할을합니다. 우리는 레일이 어디에 있는지 알고 있으며, 그 방향을 따라 가고 다시 시작하기 위해 루프를합니다!

그러나 가장 일반적인 결과는 우리가 아무것도 찾지 못한다는 것입니다. 이 경우에도 여전히 괜찮습니다. 스코어 보드의 중간 정도입니다.

풍차 비슷한 것

수용 가능한 전략이 개발되기 전에 돈키호테 (Windmill targetting) 코드 (Mk. 5)의 개발은 도전 으로 가득 차 있었고 새로운 Ant 유형이었던 코드를 포함하여 많은 반복을 거쳤다. 여왕은 자신이 Windmill의 메인 암의 중간 레일에 서 있음을 알게되면 새로운 유형의 작업자 (코드 명 LANCE) 를 생성하여 레일 의 측면 을 내려서 적의 작업자를 피하기 위해 (적의 작업자가 뱀파이어를 발견 한 것처럼) 여왕, 그들은 결국 풍차 여왕을 만날 때까지 교착 상태를 시도합니다.

여왕에 대한 두 가지 접근 방식은 비교적 명확하며 우리는 랜스가 먼저 도착 (뱀파이어 여왕이 음식을 들고있는 노동자를 관찰 할 것)에 의존하고 그 순간을 사용하여 THIEF밟지 않고 풍차 여왕에게 노동자를 낳게합니다. 뱀파이어 여왕과 인접 해 있습니다 (순식간에 음식의 흐름). 세 번째 접근 방식은 정원사에게로 끝나기 때문에 여왕은 LANCE_TIP일꾼을 낳아 정식 음식의 흐름으로 끝나는 정치적인 행동을 취합니다 .

이 공격은 윈드밀 여왕이 얼마나 많은 음식을 먹을지 결정할 수 없어서 언제 BOUNCER더 나은 희생자를 위해 산란 하고 떠날 지를 예측할 수 없게됩니다 . 그러나 풍차는 뚱뚱하고 육즙이 많은 소이기 때문에 뱀파이어가 선호하는 방식으로 작동합니다. 풍부한 젖소는 끝날 때까지 붙어 다니는 것이 더 가치가 있습니다. 풍차는 뱀파이어가 얻을 수있는 것보다 훨씬 더 많은 수천 가지 음식만으로 수백 가지의 음식을 쉽게 모을 수 있습니다 거머리에게 새로운 목표를 찾으려고 노력함으로써

Garlicked (Mk6) 업데이트는 여왕이 약간 접근하는 방식을 변경합니다. 철도 접근 방식은 동일하지만 여왕에 도달하면 약간의 변화가 있습니다. 이로 인해 단 한 명의 노동자 만 풍차 여왕에 인접하여 뱀파이어 여왕을 가능한 한 멀리 유지합니다 (풍차 노동자를 피하고 가장 중요하게는 마늘). 그 변화는 두 명의 노동자가 풍차 여왕과 인접 해있을 때 가방을 포장하고 이전한다는 사실에 기인합니다.

Renewable Energy (Mk 7)는 Windmill에 대한 변경 사항을 취소하여 코드의 시간이 100 % 거꾸로 걸리지 않아 Mk 6의 변경 사항을 대부분 취소하면서 Windmill 타겟팅 논리를 수정합니다. 수정 성공률은 약 70 %이며, 나머지 30 %는 불가피한 운이 없어서 발생합니다. 접근 벡터가 약간 변경되었습니다.

고속도로

고속도로를 쉽게 찾을 수 있습니다. 그것은 계속 확장되는 녹색의 파블입니다. 그래서, 광부와 풍차의 꿈을 찾아 분쇄 기다리고 최초의 고속도로 후 전에 것은 뱀파이어가 너무 빨리 대상으로하지 않는다는 것을 의미한다.

여왕을 찾는 것은 간단합니다. 고속도로 중심을 찾아서 기다리십시오. 그녀는 결국 올 것이다. 작업자 준비는 그녀가 중지됩니다 여부를 결정할 것 또는 우리는 또 다른 루프를 기다릴 필요가 있지만, 지연 차이의 큰하지 않습니다 결국 우리가 그녀를 잡아 훔치는 것 ALL 그녀의 음식을.

뱀파이어가 음식이 1000 이상이면 고속도로를 무시합니다. 그 시점에서 더 이상 중요하지 않기 때문입니다.


1
@trichoplax 문제 없습니다; 다시 살펴볼 시간이 생기면 작업자가 흔들리지 않아도 개선 할 수있는 부분을 확인할 수 있습니다. 이것이 이루어질 때까지, 나는 상대방이 찾기 쉽기를 기다리는 것이 가장 중요하다고 생각합니다!
Dave

9
이것은 정말로 의미합니다.
Destructible Lemon

2
trichoplax는 이러한 취약점 악용 전략을 명시 적으로 허용했습니다
pppery

1
나는 동의하기 때문에 "이것은 정말 의미가있다"고 찬성했고 그것은이 콘테스트에서 구체적으로보고 싶었던 것 중 하나입니다 ...
trichoplax

1
예. 슈퍼 평균. 위안이라면 라인 지우개가 목표 패턴을 계속 유지하기 때문에 실제 게임 (이것과 그 희생자와 다른 플레이어와 함께)에서는 거의 작동하지 않습니다.
Dave

11

랭턴의 개미

모든 답변에는 Formic Functions Framework 형식의 유사한 하위 수준 논리가 포함됩니다. "높은 수준의 논리가 여기에서 시작됨"은 프레임 워크 코드의 끝을 나타냅니다.

// FORMIC FUNCTIONS FRAMEWORK //
// Version 1.0                //

var WHITE = 1;
var QUEEN = 5;
var HERE = 4;
var MY_VO = view[HERE];
var ME = MY_VO.ant;
var NOP = move(HERE);

var ORTHOGONALS = [1, 3, 5, 7];
var DIAGONALS = [0, 2, 6, 8];
var DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
var ALL_CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
var VIEW_ORIENTATIONS = [
  [0,1,2,
   3,4,5,
   6,7,8],

  [6,3,0,
   7,4,1,
   8,5,2],

  [8,7,6,
   5,4,3,
   2,1,0],

  [2,5,8,
   1,4,7,
   0,3,6]
];

function rotateCW(cell, amount) {
  if (cell === HERE) return cell;
  var order = [0, 1, 2, 5, 8, 7, 6, 3];
  return order[(order.indexOf(cell) + amount + 8) % 8];
}

function isDiagonal(cell) {
  return DIAGONALS.includes(cell);
}
function isOrthogonal(cell) {
  return ORTHOGONALS.includes(cell);
}

function move(cell) {
  return {cell: cell};
}
function moveMany(cells) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(move(cells[i]));
  return p;
}

function color(cell, col) {
  return {cell: cell, color: col};
}
function colorMany(cells, col) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(color(cells[i], col));
  return p;
}

function spawn(cell, type) {
  return {cell: cell, type: type};
}
function spawnMany(cells, type) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(spawn(cells[i], type));
  return p;
}

function isSane(action, ant) {
  // TODO: Minimize this
  if (ant === undefined || !ant.isObject) ant = ME;
  if (action === undefined || action.cell < 0 || action.cell >= 9) return false;
  if (action.color !== undefined) {
    if (action.color < 1 || action.color > 8) return false;
    return true;
  }
  else if (action.type !== undefined) {
    if (action.type < 1 || action.type > 4) return false;
    if (ant.type !== QUEEN || ant.food === 0) return false;
    if (isOccupied(action.cell, ant) || view[action.cell].food !== 0) return false;
    return true;
  }
  else {
    if (isOccupied(action.cell, ant) && action.cell !== HERE) return false;
    return true;
  }
}
function isOccupied(cell, ant) {
  if (ant === undefined || !ant.isObject) ant = ME;
  return view[cell].ant !== null || (view[cell].food > 0 && ant.type !== QUEEN && ant.food === 1);
}
function isColoringMeaningful(action) {
  return isSane(action) && action.color !== undefined && view[action.cell].color !== action.color;
}

function test(cell, test) {
  var vo = view[cell];
  return (test.color === undefined || test.color === vo.color) &&
         (test.food === undefined || test.food === vo.food) &&
         (test.ant === undefined || test.ant === vo.ant || (
           (test.ant !== null && vo.ant !== null) &&
           (test.ant.food === undefined || test.ant.food === vo.ant.food) &&
           (test.ant.type === undefined || test.ant.type === vo.ant.type) &&
           (test.ant.friend === undefined || test.ant.friend === vo.ant.friend)
         ));
}

function findOrientation(tests) {
  var best = {orientation: null, matches: []};
  for (var o = 0; o < VIEW_ORIENTATIONS.length; o++) {
    var matches = [];
    for (var i = 0; i < tests.length; i++) {
      if (test(VIEW_ORIENTATIONS[o][tests[i].cell], tests[i])) {
        matches.push(tests[i]);
      }
    }
    if (matches.length > best.matches.length) {
      best.orientation = o;
      best.matches = matches;
    }
  }

  return best;
}

function orientCells(orientation, cells) {
  if (orientation === null || orientation < 0 || orientation >= 4) orientation = 0;
  for (var i = 0; i < cells.length; i++) {
    cells[i] = VIEW_ORIENTATIONS[orientation][cells[i]];
  }
  return cells;
}

function findFirst(func, cells) {
  if (cells === undefined) cells = ALL_CELLS;
  for (var i = 0; i < cells.length; i++) {
    if (func(cells[i])) return cells[i];
  }
  return null;
}
function findAll(func, cells) {
  if (cells === undefined) cells = ALL_CELLS;
  var found = [];
  for (var i = 0; i < cells.length; i++) {
    if (func(cells[i])) found.push(cells[i]);
  }
  return found;
}

// HIGH-LEVEL LOGIC STARTS HERE //
var ROAD_COL = 3;
var SIM_COLS = [ 1, 8, 5, 6, 4, 2, 7, 3]; // SIM_COLS.length must be greater or equal to SIM_ROTS.length
var SIM_ROTS = [-1,-1,+1,-1,-1,+1,-1,-1];
// Here are some additional rulesets to play around with:
// [+1,-1,+1,-1,+1,-1,+1,-1] // Classic Langton's ant, extended to use all 8 colors cyclically
// [+1,+1,-1,+1,-1,+1,+1]    // Produces a very interesting highway
// [-1,-1,+1,-1,-1,+1,-1,-1] // The default one -- chosen because it produces a highway nearly instantly, and the highway itself is pretty efficient
// [-1,+1,-1,-1,-1,+1,+1,-1]
// [-1,-1,+1,-1,-1,+1,-1,-1]
// [-1,+1,-1,-1,-1,+1,+1,-1]
// [+1,-1,+1,+1,+1,-1]

var ANCHOR = 1;
var TAIL = 2;

var DEBUG_MODE = false;

function getSimColIndex(cell) {
  return Math.max(SIM_COLS.lastIndexOf(view[cell].color, SIM_ROTS.length - 1), 0);
}
function getNextSimCol(simColIndex) {
  return SIM_COLS[(simColIndex + 1) % SIM_ROTS.length];
}
function getSimRot(simColIndex) {
  return SIM_ROTS[simColIndex];
}

function run() {
  switch (ME.type) {
    case QUEEN: {
      var anch = findFirst(c => test(c, {ant: {type: ANCHOR, friend: true}}), DIRECTIONS);
      if (anch !== null) {
        if (isOrthogonal(anch)) {
          var tail = findFirst(c => test(c, {ant: {type: TAIL, friend: true}}), DIAGONALS);
          if (tail !== null) {
            return [move(rotateCW(anch, -2 * getSimRot(getSimColIndex(HERE))))].filter(isSane)[0] || NOP;
          } else {
            var nanch = rotateCW(anch, -getSimRot(getSimColIndex(anch)));
            return color(nanch, getNextSimCol(getSimColIndex(nanch)));
          }
        } else {
          return NOP;
        }
      } else {
        var tailO;
        if (ME.food === 2) {
          return spawnMany(ORTHOGONALS, TAIL).filter(isSane)[0] || NOP;
        } else if (ME.food === 1 && (tailO = findOrientation([{cell: 1, ant: {type: TAIL, friend: true}}])).orientation !== null) {
          return spawnMany(orientCells(tailO.orientation, [3, 5]), ANCHOR).filter(isSane)[0] || NOP;
        }

        var f;
        if ((f = findFirst(c => test(c, {food: 1})))) {
          return move(f);
        }

        if (test(HERE, {color: ROAD_COL})) {
          return moveMany(orientCells(findOrientation([{cell: 0, color: ROAD_COL}]).orientation, [8, 6, 2])).filter(a => isSane(a) && !test(a.cell, {color: ROAD_COL}))[0] || moveMany(DIAGONALS).filter(isSane)[0] || NOP;
        } else {
          return color(HERE, ROAD_COL);
        }
      }
      break;
    }
    case ANCHOR: {
      var queen = findFirst(c => test(c, {ant: {type: QUEEN, friend: true}}), DIAGONALS);
      var tail = findFirst(c => test(c, {ant: {type: TAIL, friend: true}}), ORTHOGONALS);
      var qp = [rotateCW(queen, -1), rotateCW(queen, +1)];
      var tp = [rotateCW(tail, -2), rotateCW(tail, +2)];
      for (var i = 0; i < qp.length; i++) {
        for (var j = 0; j < tp.length; j++) {
          if (qp[i] === tp[j]) return [move(qp[i])].filter(isSane)[0] || NOP;
        }
      }
      return NOP;
      break;
    }
    case TAIL: {
      var anch = findFirst(c => test(c, {ant: {type: ANCHOR, friend: true}}), DIAGONALS);
      if (anch !== null) {
        var rot = getSimRot(getSimColIndex(anch));
        var nanch = rotateCW(anch, rot);
        if (test(nanch, {ant: {type: QUEEN, friend: true}})) return [move(rotateCW(anch, -rot))].filter(isSane)[0] || NOP;
        return [move(nanch)].filter(isSane)[0] || NOP;
      } else {
        return NOP;
      }
      break;
    }
  }
}

var output = run();
if (isSane(output)) return output;
else {
  if (DEBUG_MODE) {
    return;
  } else {
    return NOP;
  }
}

랭턴의 개미 ( "RL") 랭턴의 개미 ( "LLRLLRLL")


소개

이것은 Formic Functions QOTH 과제의 범위 내에서 Langton의 개미를 구현 한 것입니다. 또한 보너스 로 Langton 개미의 멀티 컬러 변형 을 지원합니다 . 또한 최대 8 가지 색상 의 전체 팔레트를 활용할 수있었습니다 . 또한,이 개미 는 게임 단계 로 시뮬레이션의 단계 를 완료 합니다.

불행히도, Langton 개미의 더 흥미로운 변형은 8 가지 이상의 색상을 취하므로 대신 효율적인 색상을 설정했습니다. 지정된 시간 제한 내에서 가장 많은 양의 땅을 덮고있는 개미를 찾기위한 보충 프로그램을 작성했으며 "RRL"규칙 세트의 여러 변형을 우연히 발견했습니다. 그들은 모두 15000 단계 내에서 4168 셀을 커버 합니다.

이제 4000 개의 세포가 끔찍합니다! 즉, 평균적으로이 항목은 4 가지 음식으로 게임을 종료합니다 . 그리고 그것은 빈 보드에 있습니다! 솔직히 Brownian Jig 는 이것보다 낫습니다. 요컨대, 이것은 점수 판에 위치 할 때 심각한 경쟁자가 아닙니다. 그러나 그것이 할 수있는 일은 다른 항목을 엉망으로 만드는 것입니다. 그리고 이것이 내가 이것을 제출하는 것을 귀찮게 한 유일한 이유입니다. 이 항목과 색상에 크게 의존하는 항목 간에는 매우 복잡한 상호 작용이 자주 나타납니다. 그리고 색에 의존하는 사람들은 대개 고통을 겪습니다.


설명

색상 ( SIM_COLS)에는 SIM_ROTS여왕이 향하는 방향을 변경하는 데 사용 하는 해당 회전 ( )이 있습니다. +1시계 방향 회전 ( "R"), -1시계 반대 방향 회전 ( "L")을 의미합니다. 고전 랭턴의 개미가 될 것이다 SIM_COLS = [ 1, 8], SIM_ROTS = [+1,-1]. SIM_COLS배열 은 배열에 일치하는 요소가없는 모든 요소를 ​​효과적으로 버립니다 SIM_ROTS. 잘린 SIM_COLS배열에 포함되지 않은 모든 색상은 색상 0으로 처리되며 개미 자체에서 생성되지 않습니다.

다른 적절한 개미와 마찬가지로이 음식은 충분한 음식을 모아서 실제로 일을 시작할 수 있습니다 . 2 음식 이 필요합니다 .

초기 스크램블을 마친 여왕은 앵커테일 이라는 두 개의 개미 를 낳습니다 . 여왕은 여왕과 직교 (셀 1, 3, 5, 7)에 인접하여 꼬리를 먼저 생성합니다. 그런 다음 그녀는 여왕에게 직교하고 꼬리에 대각선으로 (셀 0, 2, 6, 8) 앵커를 생성합니다.

동작은 서로 다른 두 단계로 반복되는 주기로 구성됩니다.

1 단계

꼬리 : 여왕이 2 단계 전에 시뮬레이션을 점유하고 있던 셀을 검색합니다. 그것은 앵커 아래의 색과 여왕의 존재 (또는 그 부족)를 사용하여 대상 세포를 정확하게 결정합니다. 향후 업데이트에서 해결 될 재난이 발생하기 쉽습니다.

앵커 : 아무것도하지 않습니다.

여왕 : 닻을 찾아 개미가가는 방향의 역수로 취급합니다. 그런 다음 퀸 아래의 색상에 따라 방향이 회전합니다. 여왕은 회전 방향으로 표시된 셀로 이동합니다.

2 단계

꼬리 : 아무것도하지 않습니다.

앵커 : 꼬리에 대각선으로 인접하고 여왕에 직교 적으로 인접한 셀을 검색하여 이동합니다. 그러한 셀은 최대 하나입니다.

Queen : 1 단계의 Tail과 마찬가지로 2 단계 전에 시뮬레이션을 점유 한 셀을 검색하고 주기적으로 색상을 변경합니다. 대상 셀을 정확하게 결정하기 위해 앵커 아래의 색상을 사용합니다. 일어날 수있는 최악의 재앙은 잘못된 세포를 색칠하는 것이며, 개미의 궤적을 바꾸는 동안, 다른 개미의 존재로 인해 궤적이 바뀌기 때문에 실제로 문제가되지는 않습니다.

해야 할 일 결정

여왕은 꼬리를 직각으로 검색하여 현재 단계를 결정합니다. 그녀가 그것을 발견하면, 그녀는 1 단계에 있습니다. 그렇지 않으면, 그녀는 2 단계에 있습니다. 드문 경우에, 앵커는 대각선으로 자신에게 인접 해있을 수도 있습니다. 이 경우, 그녀는 아무것도하지 않을 것입니다.

앵커는 단계를 결정할 논리가 없습니다. 항상 여왕에 직교하고 꼬리에 대각선으로 인접하도록 노력합니다. 그러한 세포가 없으면 단순히 움직이지 않습니다.

꼬리는 앵커를 대각선으로 검색하여 현재 단계를 결정합니다. 찾은 경우 1 단계에 있고 그렇지 않으면 2 단계에 있습니다.

테일 이동 중 앞서 언급 한 재난은 앵커 아래에서 색상을 변경하는 개미에 의해 유발 될 수 있습니다. 변경된 색상이 원본과 다른 회전을 나타내며 여왕이 꼬리를 보지 못하면 꼬리 이동 후의 결과 위치는 3 개의 개미의 직선입니다. 현재이 상황에 대한 해결책을 찾고 있습니다.


이것은 처음에는 진지한 경쟁자 가 아니지만 , 경기장에서 물건을 꾸미고 메타를 무색 개미쪽으로 조금 옮겨야합니다. 나는 요리를 두 번 제출했고 (그중 하나는 정말 매운 것으로 보입니다 ), 앞으로 몇 주 안에 더 많은 항목을 기대하십시오.


3
PPCG에 오신 것을 환영합니다!
Steadybox

10

지그 라트 v3.0

var clockwise = [1,2,5,0,4,8,3,6,7];
var opposite = [8,7,6,5,4,3,2,1,0];
var cyclic_cw = [0,1,2,5,8,7,6,3,0];
var worker_colors = [4,5,7,8];
var next_worker_color = [1,1,1,1,5,7,1,8,4];
var prev_worker_color = [1,1,1,1,8,4,1,5,7];
var diags = [0,2,6,8];
var orthos = [1,3,5,7];
var cleaning_color = 6;


// Borrowed from Medusa
function clean(move) {
    if (move["color"] == undefined) {
        if (view[move["cell"]].ant != null) {
            move = {cell: 4};
        }
        if (move["type"] == undefined) {
            if (view[move["cell"]].food == 1 && view[4].ant.type < 5 && view[4].ant.food > 0) {
                move = {cell: 4};
            }
        } else if (view[4].ant.type != 5 || view[4].ant.food == 0 || view[move["cell"]].food == 1) {
            move = {cell: 4};
        }
    }
    return move;
}

function worker_blank(cel) {
    return (worker_colors.indexOf(view[cel].color) < 0);
}

// Own status
var my_color = view[4].color;
var my_food = view[4].ant.food;
var my_type = view[4].ant.type;

// Random free cell
var free_cell = 4;
for (var cel = 0; cel < 9; cel++) {
    if (view[cel].ant == null) {
    free_cell = cel;
    }
}

// Check surroundings
var blanks = 0;
var outer_edge = 0;
var inner_edge = 0;
var next_edge = -1;
var prev_nonblank = -1;
var some_nonblank = -1;
var prev_cell = -1;
var next_cell = -1;
var food_cell = -1;
var nonblank_color = 0;
var cleaning_marker = -1;
var uniform = 1;
var low_type = -1;
var friend_workers = 0;
var guards = 0;
var enemies = 0;
var enemy_queens = 0;
var my_queen = -1;

if (!worker_blank(4)) {
    nonblank_color = view[4].color;
}
for (var ix = 0; ix < 8; ix++) {
    var cel = cyclic_cw[ix];
    var cel2 = cyclic_cw[ix+1];
    if (view[cel].food == 1) {
    food_cell = cel;
    }
    if (worker_blank(cel)) {
    blanks++;
    if (!worker_blank(cel2)) {
        if (worker_blank(4)) {
        outer_edge = 1;
        } else {
        inner_edge = 1;
        }
        next_edge = cel;
            prev_nonblank = cel2;
    }
    if (view[cel].color == cleaning_color) {
        cleaning_marker = cel;
    }
    } else {
    some_nonblank = cel;
    if (nonblank_color == 0) {
        nonblank_color = view[cel].color;
    } else if (view[cel].color != nonblank_color) {
        uniform = 0;
    }
    }
    if ((!worker_blank(4) && view[cel2].color == prev_worker_color[my_color] && view[cel2].ant == null) || (worker_blank(4) && !worker_blank(cel2))) {
    prev_cell = cel2;
    }
    if (!worker_blank(4) && view[cel2].color == next_worker_color[my_color] && view[cel2].ant == null) {
    next_cell = cel2;
    }
    if (view[cel].ant != null) {
    var the_ant = view[cel].ant;
    if (the_ant.friend) {
        if (low_type < 0 || the_ant.type < low_type) {
        low_type = the_ant.type;
        }
        if (the_ant.type == 4) {
        guards++;
        } else if (the_ant.type == 5) {
        my_queen = cel;
        } else {
        friend_workers++;
        }
    } else {
        enemies++;
        if (the_ant.type == 5) {
        enemy_queens++;
        }
    }
    }
}

// Queen before finding food (motile)
if (my_type == 5 && worker_blank(4)) {
    if (my_food > 1) {
    return {cell:4, color:worker_colors[1]};
    }
    if (food_cell >= 0 && my_color != 1) {
    return clean({cell:food_cell});
    }
    if (my_color == 2) {
    for (var ix = 0; ix < 4; ix++) {
        var cel = diags[ix];
        var oppo = opposite[cel];
        if (view[cel].color == 2) {
        if (view[oppo].color == 1 && worker_blank(oppo) && view[oppo].ant == null) {
            return clean({cell:oppo});
        }
                if (view[oppo].color != 2) {
            return {cell:oppo, color:1};
                }
        }
    }
        for (var ix = 0; ix < 4; ix++) {
        var cel = diags[ix];
        if (view[cel].color != 2) {
        return {cell:cel, color:2};
        }
    }
    }
    if (my_color == 1) {
    return {cell:4, color:2};
    }
    return clean({cell:free_cell});
}

// Queen after finding food (sessile)
if (my_type == 5) {
    for (var ix = 0; ix < 8; ix++) {
        cel = cyclic_cw[ix];
    if (worker_blank(cel)) {
            return {cell:cel, color:worker_colors[1]};
    }
    }

    if (my_color != worker_colors[0]) {
        if (my_food > 0) {
        return clean({cell:free_cell, type:1});
        } else {
            return {cell:4, color:worker_colors[0]};
        }
    }
    if (my_food > 0) {
    if (my_food > 3 && guards < 2) {
        return clean({cell:free_cell, type:4});
    }
    if (0 < low_type && low_type < 3) {
        return clean({cell:free_cell, type:(low_type + 1)});
    }
    }
    return {cell:4};
}

// Queen's guard

if (my_type == 4) {
    // Queen is a nbor
    if (my_queen >= 0) {
    if (enemy_queens > 0) {
        return {cell:4};
    }
    if (my_queen == 1) {
        return clean({cell:5});
    }
    return clean({cell:clockwise[my_queen]});
    }
    // Try to get to queen
    if (prev_cell >= 0) {
    return clean({cell:prev_cell});
    }
    // Wander
    return clean({cell:free_cell});
}

// Worker

// Create new ziggurat
if (blanks == 8 && cleaning_marker < 0 && my_color != cleaning_color) {
    if (worker_colors.indexOf(my_color) >= 0) {
    return {cell:free_cell, color:my_color};
    }
    return {cell:free_cell, color:worker_colors[0]};
}

var front = view[1].color;
if (!worker_blank(4) && !worker_blank(1) && my_color != front) {
    if (view[7].color == front || (view[6].color == front && view[8].color == front)) {
        return {cell:4, color:front};
    }
}

if (my_food == 0) {
    // Grab food
    if (food_cell >= 0 && (!worker_blank(4) || !worker_blank(food_cell))) {
        return clean({cell:food_cell});
    }

    // Clear marked uniform region
    if (my_color == cleaning_color && uniform) {
    if (blanks < 7) {
        return {cell:some_nonblank, color:1};
    } else if (blanks == 7) {
        return {cell:some_nonblank, color:cleaning_color};
    }
    }

    // Follow cleaning color
    if (blanks == 8) {
    if (cleaning_marker < 0 || my_color == cleaning_color) {
        return {cell:4, color:1};
    } else if (cleaning_marker >= 0) {
        return clean({cell:cleaning_marker});
    }
    }

    // Dive into uniform region
    if (blanks > 3 && worker_blank(4) && worker_blank(1) && !worker_blank(2) && view[2].color == view[5].color && view[2].color == view[8].color) {
    return clean({cell:2});
    }

    // Mark uniform region for clearing
    if (!worker_blank(4) && uniform && (blanks < 4 || (blanks < 7 && ((worker_blank(1) && worker_blank(7)) || (worker_blank(3) && worker_blank(5)))))) {
    return {cell:4, color:cleaning_color};
    }

    // Extend edge
    if (outer_edge) {
    var new_color = 0;
    var cl = clockwise[next_edge];
    var cl2 = clockwise[cl];
    if (!worker_blank(1) && view[7].color == view[1].color) {
        new_color = view[1].color;
    } else if (!worker_blank(3) && view[5].color == view[3].color) {
        new_color = view[3].color;
        } else if (!worker_blank(cl2) && view[cl].color == next_worker_color[view[cl2].color]) {
        if (cl > 1) {
        new_color = view[cl].color;
        } else {
        new_color = next_worker_color[view[cl].color];
        }
    } else if (!worker_blank(cl)) {
        new_color = next_worker_color[view[cl].color];
        } else if (prev_nonblank >= 0) {
            new_color = next_worker_color[prev_nonblank];
    }
    if (new_color == 0 && blanks < 2) {
        new_color = worker_colors[0];
    }
        if (new_color > 0) {
            return {cell:4, color:new_color};
        } else {
            return clean({cell:next_edge});
        }
    }

    // Escape from hole
    if (worker_blank(4) && blanks == 0) {
        return {cell:4, color:next_worker_color[nonblank_color]};
    }

    // Go outside or fill it
    if (inner_edge && next_edge >= 0) {
    if (friend_workers > 1) {
        return clean({cell:free_cell});
    }
        if (blanks == 4 && prev_nonblank >= 0) {
            return {cell:next_edge, color:next_worker_color[view[prev_nonblank].color]};
        }
    if (view[next_edge].ant == null) {
            return clean({cell:next_edge});
    }
    return {cell:4};
    }

    // Go toward border
    if (!worker_blank(4) && next_cell >= 0 && next_cell != 1) {
    return clean({cell:next_cell});
    }

    // Wander
    return clean({cell:free_cell});
}

if (my_food > 0) {
    // Take food to queen
    if ((prev_cell >= 0 && prev_cell != 1) || (prev_cell >= 0 && worker_blank(4))) {
    return clean({cell:prev_cell});
    }

    // Wander
    if (worker_blank(free_cell) && !worker_blank(4)) {
    return {cell:4};
    }
    return clean({cell:free_cell});
}

return clean({cell:free_cell});

작동 원리

이 개미는 블랙홀메두사 . 여왕은 음식을 대각선으로 찾는 것으로 시작합니다. 음식이 2 단위가되면 맛이 좋아져 두 명의 일꾼이됩니다. 노동자들은 여왕 주위를 돌면서 4 가지 색상을 사용하여 줄무늬가있는 지역 ( "지구라트")을 만듭니다. 노동자가 음식을 찾으면 줄무늬를 따라 광장 중앙에 앉아 여왕에게 가져갑니다. 노동자가 원래 두 사람 중 하나 였다면 여왕은 새로운 노동자를 만든다. 그렇지 않으면, 그녀는 음식을 저장합니다.

코멘트

버전 2.0 은 4 가지 색상을 사용하므로 개미가 쉽게 길을 잃지 않게됩니다. 노동자 창출 계획은 또한 먼저 많은 노동자를 만들고 지역을 성장시킨 다음 리더 보드에 음식을 쌓아두기 위해 개정되었습니다. 불법적 인 움직임에 대한 더 많은 검사도 있습니다.

버전 2.1 에는 개선 된 지그 구트 구성 루틴이 있습니다. 작업자는 때때로 두 가지 옵션 중에서 색상을 선택할 수 있습니다. 이로 인해 스트라이프 패턴이 더 무작위로 만들어져 뱀파이어를 속일 수 있습니다. 노동자들은 움직이기 전에 때때로 두 가지 색을 내려 놓으면 지그 구트가 더 빨리 자랍니다. ziggurat 내부에서 작업자는 때때로 무한 루프를 피하기 위해 무작위로 이동하여 특정 지역 불일치를 수정하려고합니다. 여왕은 자신의 운동 단계에서 흔적을 피하는 것에 대해 더 똑똑합니다. 마지막으로, Sessile Queen이 공격을 당하면, 그녀는 새로운 노동자 파열을 일으켜 싸우고, 공격자가 기존의 모든 노동자에게서 그녀를 차단하는 트레일-지우개 인 경우 복구하는 데 도움이됩니다.

버전 3.0 에는 구성 루틴이 더 많이 조정되었습니다. 블랙홀과 산불에 대한 (대부분의 테스트되지 않은) 대책으로서, 균일 한 색의 영역을 발견 한 작업자는 지우려고합니다. 여왕은 더 이상 공격을받을 때 수십 명의 노동자를 낳지 않습니다. 대신, 그녀는 주위를 공전하는 보호자 개미 한 쌍을 가지고있다. 그녀는 또한 음식을 저장하기 전에 더 오래 기다릴 것입니다.

나는 JS를 정말로 모른다. 그래서 코드는 끔찍한 혼란이다.

줄무늬 영역의 사진은 다음과 같습니다.

지구라트


보기에 아름답습니다. 성장하는 결정의 결함과 같이 줄무늬에 때때로 불완전한 결함이 있다는 것이 흥미 롭습니다. 그러나 여전히 여왕으로 인도되어 노동자들에게 아무런 문제를 일으키지 않는 것처럼 보입니다.
trichoplax

1
나는이 패턴이 불완전한 이상을
입었을

1
@trichoplax 방금 봇을 업데이트했습니다. 그것은 지금 불법적 인 행동을해서는 안되며, 전반적으로 조금 더 똑똑합니다.
Zgarb

1
그리고 최신 버전은 약간의 어려움을 겪고있는 하나의 트레일 지우개에 의한 공격에서 살아남을 수있는 것처럼 보입니다. 둘 이상의 침입이 발생하면 어떻게되는지 확실치 않습니다
pppery

1
@trichoplax 지금 수정해야합니다. 다른 개선 사항도 추가했습니다.
Zgarb

9

산불 Mk.3

모든 대답은 동일한 하위 수준 도우미 기능 집합을 공유합니다. 이 답변과 관련된 코드를 보려면 "고수준 논리가 여기서 시작됩니다"를 검색하십시오.

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || (movement.cell|0) !== movement.cell || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if((movement.type|0) !== movement.type || movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if((movement.color|0) !== movement.color || movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(movement.cell !== CENTRE && view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function ant_type_near(p, friend) {
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && ant_type_at(i, friend) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand, avoidedColours) {
  if(!avoidedColours) {
    avoidedColours = colourBand;
  }
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !avoidedColours.contains(view[rot[0]].color) &&
        avoidedColours.contains(view[rot[5]].color) &&
        avoidedColours.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !avoidedColours.contains(view[rot[0]].color) &&
        avoidedColours.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (avoidedColours.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!avoidedColours.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side, resultFn) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  if(!resultFn) {
    resultFn = (i) => ({cell: i});
  }

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => ((fn(order[i+1]) && !fn(order[i])) ? resultFn(order[i]) : null),
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var groundCol = 5;
var poisonCol = 8;

var DIRECTOR = 1;
var FORAGER0 = 2;
var FORAGER1 = 3;
var FORAGER2 = 4;
var MAX_FORAGER_TYPES = 3; // Worker creation throttle
var MIN_FOOD = 3; // Don't embarrass ourselves when things go bad
var MAX_FOOD_SPAWN = 80; // If we're doing well, don't spoil it all

var GROUND_COLOURS = colour_band([groundCol, poisonCol]);
var POISON_COLOURS = colour_band([poisonCol]);
var SAFE_COLOURS = random_colour_band(colours_excluding([WHITE, groundCol, poisonCol]));
var INITIAL_OBSTACLES = random_colour_band(colours_excluding([WHITE]));

function ground_at(i) {
  return GROUND_COLOURS.contains(view[i].color);
}

function unlaiden_friend_at(i) {
  return friend_at(i) && (friend_at(i) === QUEEN || !view[i].ant.food);
}

function obstacle_at(i) {
  // foes are unpredictable, so don't consider them obstacles
  return view[i].food || unlaiden_friend_at(i) || GROUND_COLOURS.contains(view[i].color);
}

function wait_if_blocked(i) {
  return friend_at(i) ? {cell:CENTRE} : {cell: i};
}

function move_director(me, buddies) {
  if(!buddies[QUEEN]) {
    // Lost the queen!
    return go_anywhere();
  }

  var rot = identify_rotation((rot) => (
    friend_at(rot[0]) === QUEEN || friend_at(rot[1]) === QUEEN
  ));

  var ready = (friend_at(rot[1]) === QUEEN && view[rot[1]].color === groundCol);
  var shift = (view[rot[2]].color === groundCol && GROUND_COLOURS.contains(view[rot[5]].color));

  return best_of([
    // Ensure we never end up underground unless we mean to, and provide a
    // base poison layer to help workers find the right side if lost
    {cell: CENTRE, color: poisonCol},
//    {cell: rot[5], color: poisonCol},
    {cell: rot[3], color: poisonCol},

    // Move up to avoid own line after wrapping (us being underground is a signal)
    (ready && shift) && {cell: rot[2]},

    // Advance
    (ready && !shift) && {cell: rot[5]},

    // Make the poison layer more solid if we have extra time
    {cell: rot[7], color: poisonCol},
    {cell: rot[6], color: poisonCol},
    {cell: rot[8], color: poisonCol},

    // Don't lose the queen
    NOP
  ]);
}

function move_forager(me, buddies) {
  var underground = GROUND_COLOURS.contains(view[CENTRE].color);
  var buried = 0;
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && GROUND_COLOURS.contains(view[i].color)) {
      ++ buried;
    }
  }
  var travelCol = underground ? POISON_COLOURS : SAFE_COLOURS;

  if(buddies[DIRECTOR]) {
    // We've somehow got in the way of the line; get out of the way
    return try_all_angles((rot) =>
      ((friend_at(rot[6]) === DIRECTOR || friend_at(rot[7]) === DIRECTOR) &&
      best_of([{cell: rot[0]}, {cell: rot[1]}, {cell: rot[2]}])));
  }

  if(me.food) {
    // We have food for the queen; run ahead to find her as fast as we can

    return best_of([
      // Identify confusing pinch points and close them (don't get stuck on islands)
      try_all_angles((rot) => (
        obstacle_at(rot[1]) && obstacle_at(rot[7]) &&
        !obstacle_at(rot[5]) && !GROUND_COLOURS.contains(view[CENTRE].color)
      ) && {cell: CENTRE, color: groundCol}),

      // We're enclosed; mark this as a dead-end
      (buried >= 7) && {cell: CENTRE, color: poisonCol},

      // Race to queen, but don't climb over each other and cause a blockage
      follow_edge(obstacle_at, SIDE_RIGHT, wait_if_blocked),

      // Lost? Travel quickly to find the surface again
      fast_diagonal.bind(null, travelCol),

      // Totally lost
      go_anywhere
    ]);
  }

  if(buddies[QUEEN]) {
    // Don't overtake the queen!
    return NOP;
  }

  // Paint the ground
  if(!underground) {
    return {cell: CENTRE, color: groundCol};
  }

  return best_of([
    // Unpaint small islands which would confuse us or our buddies
    (buried >= 3) && try_all_angles((rot) => (
      !view[rot[0]].ant &&
      GROUND_COLOURS.contains(view[rot[0]].color) &&
      !GROUND_COLOURS.contains(view[rot[1]].color) &&
      !GROUND_COLOURS.contains(view[rot[3]].color)
    ) && {cell: rot[0], color: SAFE_COLOURS.next(WHITE)}),

    (buried >= 3) && try_all_angles((rot) => (
      !view[rot[1]].ant &&
      GROUND_COLOURS.contains(view[rot[1]].color) &&
      !GROUND_COLOURS.contains(view[rot[0]].color) &&
      !GROUND_COLOURS.contains(view[rot[2]].color)
    ) && {cell: rot[1], color: SAFE_COLOURS.next(WHITE)}),

    // Follow line
    follow_edge(ground_at, SIDE_RIGHT, wait_if_blocked),

    // Disoriented; find the surface again
    fast_diagonal.bind(null, travelCol),

    // Totally lost; random walk
    {cell: 0}
  ]);
}

function move_queen(me, buddies) {
  if(buddies[DIRECTOR]) {
    var rot = identify_rotation((rot) => (
      (friend_at(rot[7]) === DIRECTOR && view[rot[7]].color !== groundCol) ||
      (friend_at(rot[5]) === DIRECTOR && view[rot[5]].color === groundCol) ||
      friend_at(rot[8]) === DIRECTOR
    ));

    var rand14 = rot === ROTATIONS[0];
    var existing = friend_at(rot[0]);
    var nextType = existing ? (existing + 1) : FORAGER0;
    var workerSpawn = (
      me.food > MIN_FOOD && me.food < MAX_FOOD_SPAWN &&
      view[rot[3]].color === groundCol && // Don't spawn if disrupted
      view[rot[0]].color === WHITE && // Don't spawn while stuck in a nest
      view[rot[1]].color === WHITE &&
      !friend_at(rot[1]) && !friend_at(rot[3]) && !friend_at(rot[6]) &&
      (existing || rand14) // reduce likelihood of spawning new chains
    );

    return best_of([
      // Paint ground
      {cell: CENTRE, color: groundCol},

      // Follow director up slopes
      (friend_at(rot[5]) === DIRECTOR) && {cell: rot[2]},
      (friend_at(rot[5]) === DIRECTOR) && {cell: rot[1]},

      // Recognise likely erasure issues and correct
      view[rot[2]].color === groundCol && GROUND_COLOURS.contains(view[rot[8]].color) &&
        {cell: CENTRE, color: groundCol},

      // Clear cells which could confuse workers
      GROUND_COLOURS.contains(view[rot[2]].color) && {cell: rot[2], color: SAFE_COLOURS.next(WHITE)},

      // Spawn new workers when ready (throttle probabilistically)
      (workerSpawn && nextType < FORAGER0 + MAX_FORAGER_TYPES) && {cell: rot[1], type: nextType},

      // Follow director along flat planes
      (friend_at(rot[8]) === DIRECTOR) && {cell: rot[5]},

      // Don't lose director
      NOP
    ]);
  }

  return best_of([
    // Begin wildfire
    (me.food >= MIN_FOOD + MAX_FORAGER_TYPES + 1) && try_all_angles((rot) =>
      (view[rot[5]].color !== groundCol && sanity_check({cell: rot[5]}) &&
        {cell: rot[8], type: DIRECTOR})),

    // Hungry or too crowded to begin; frantically find food
    grab_nearby_food,
    fast_diagonal.bind(null, SAFE_COLOURS, INITIAL_OBSTACLES),
    go_anywhere,
    {cell: 1, color: SAFE_COLOURS.next(WHITE)}
  ]);
}

return play_safe(move_agent([
  DIRECTOR, move_director,
  FORAGER0, move_forager,
  FORAGER1, move_forager,
  FORAGER2, move_forager,
  QUEEN, move_queen,
]));

산불 개미는 보드를 쓸어 가며 길에있는 모든 것을 삼켜 버립니다. 이것은 블랙홀 (Draco18s의) 개념을 나의 법의학 개미 와 혼합하여 영감을 얻었습니다 .

여왕은 음식을 빨리 모아서 시작합니다. 일단 그녀가 충분 해지면, 그녀는 직선으로 움직이기 시작하고 몇몇 조력자를 낳을 것입니다. 이 조력자들은 음식을 찾으면 따라 잡기 위해 질서 정연하게 그녀를 따라갈 것입니다.

Mk.2는 전문 개미를 사용하여 여왕이 자신의 지시를 유지하도록 돕고,이 개미는 잃어버린 노동자들이 밴드의 올바른면을 찾도록 돕기 위해 검은 흔적을 내려 놓습니다. 더 나은 작업자 탐색 기능과 결합하여 경쟁 개미와 혼합하면 훨씬 더 나은 성능을 제공합니다. 그것은 심지어 빨간 점의 둥지를 치고 난 후에도 결국에는 회복됩니다.

Mk.2c는 확률을 사용하여 근로자 인구를 제어하고 상당히 잘 관리하는 것 같습니다. 노동자들은 여전히 ​​내가 원하는 것보다 더 자주 불속에서 길을 잃고 있지만, 그럼에도 불구하고 혼자서 인상적인 보드를 인계받습니다.

Mk.3은 "단일 퀸"항목으로 생성 된 대각선 빨간색 선으로부터 보호 기능을 추가하여 유사한 상황에서도 도움이됩니다. 근로자들은 이제 무작위 우회에 의해 산만해질 가능성이 훨씬 적으며 성능이 더 좋아 보입니다.

다음은 프로토 타입 중 하나의 결과입니다.

불

(그렇습니다, 그것은 865 명의 노동자 개미입니다. 그리고 er, 5 개의 음식)


경쟁사 스크린 샷은 다음과 같습니다.

정화 불


그리고 내 마음 속에있는 개미 (해당 음악)를 상상하는 방법은 다음과 같습니다.

파프리카 퍼레이드


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Martin Ender

음악을들을 수 없습니다 ...
NH.

1
@NH. 개구리 / 카오스 / 일반 광기는 영화 파프리카에서 온 것입니다. 음악을 알고 싶다면 그것을보십시오!
Dave

9

빛의 속도

모든 답변에는 Formic Functions Framework 형식의 유사한 하위 수준 논리가 포함됩니다. "높은 수준의 논리가 여기에서 시작됨"은 프레임 워크 코드의 끝을 나타냅니다.

 //  FORMIC FRAMEWORK  //
// Version 6.1.10     //
const WHITE = 1;
const QUEEN = 5;
const CENTER = 4;
const HERE = view[CENTER];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const ROTATIONS = [
  [0, 1, 2,
   3, 4, 5,
   6, 7, 8],

  [6, 3, 0,
   7, 4, 1,
   8, 5, 2],

  [8, 7, 6,
   5, 4, 3,
   2, 1, 0],

  [2, 5, 8,
   1, 4, 7,
   0, 3, 6]
];
const NEIGHBORS = [
  [1, 4, 3],
  [2, 5, 4, 3, 0],
  [5, 4, 1],
  [0, 1, 4, 7, 6],
  [0, 1, 2, 5, 8, 7, 6, 3],
  [8, 7, 4, 1, 2],
  [3, 4, 7],
  [6, 3, 4, 5, 8],
  [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = false;
function dump() {
  if (DEBUG_MODE) {
    throw "dump() not implemented";
  }
}
function log(...args) {
  if (DEBUG_MODE) {
    console.log(...args);
  }
}
function error(...args) {
  log("Transformed view state:", view);
  log(...args);
  throw "A critical error has occurred!";
}

function createArray(func, length) {
  const arr = [];
  for (let i = 0; i < length; i++) {
    arr.push(func(i, arr));
  }
  return arr;
}

class Test {
  run(cell) {
    error("No run method defined for this instance of Test:", this);
  }
  find(cells = CELLS) {
    return cells.find((c) => this.run(c));
  }
  findIndex(cells = CELLS) {
    return cells.findIndex((c) => this.run(c));
  }
  filter(cells = CELLS) {
    return cells.filter((c) => this.run(c));
  }
  every(cells = CELLS) {
    return cells.every((c) => this.run(c));
  }
  some(cells = CELLS) {
    return cells.some((c) => this.run(c));
  }
  count(cells = CELLS) {
    return this.filter(cells).length;
  }
  invert() {
    return new InverseTest(this);
  }
  and(test) {
    return new EveryTest(this, test);
  }
  or(test) {
    return new SomeTest(this, test);
  }
}

class InverseTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return !this.test.run(cell);
  }
  invert() {
    return this.test;
  }
}

class CombinedTest extends Test {
  constructor(...tests) {
    super();
    this.tests = tests;
  }
  append(test) {
    this.tests.push(test);
    return this;
  }
}
class EveryTest extends CombinedTest {
  run(cell) {
    return this.tests.every((test) => test.run(cell));
  }
  and(test) {
    return this.append(test);
  }
}
class SomeTest extends CombinedTest {
  run(cell) {
    return this.tests.some((test) => test.run(cell));
  }
  or(test) {
    return this.append(test);
  }
}

class ColorTest extends Test {
  constructor(color) {
    super();
    this.color = color;
  }
  run(cell) {
    return view[cell].color === this.color;
  }
}
class ColorBandTest extends SomeTest {
  constructor(colorBand) {
    super(...colorBand.map((color) => new ColorTest(color)));
  }
}

class FoodTest extends Test {
  constructor(hasFood = true) {
    super();
    this.food = hasFood ? 1 : 0;
  }
  run(cell) {
    return view[cell].food === this.food;
  }
}

class AntTest extends Test {
  constructor(friend, type, food) {
    super();
    this.friend = friend;
    this.type = type;
    this.food = food;
  }
  run(cell) {
    const ant = view[cell].ant;
    return ant !== null && (this.type === undefined || ant.type === this.type) && (this.friend === undefined || ant.friend === this.friend) && (this.food === undefined || (this.food ? ant.food > 0 : ant.food === 0));
  }
}

class NeighborTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return this.test.some(NEIGHBORS[cell]);
  }
}

class MatchTest extends Test {
  constructor(matches) {
    super();
    this.matches = matches;
  }
  run(cell) {
    return this.matches[cell];
  }
}

class CustomTest extends Test {
  constructor(func, ...args) {
    super();
    this.func = func;
    this.args = args;
  }
  run(cell) {
    return this.func(cell, ...this.args);
  }
}

class Action {
  constructor(cell, test) {
    this.cell = cell;
    this.test = test;
  }

  valid() {
    return this.cell >= 0 && this.cell < 9 && (!this.test || this.test.run(this.cell));
  }
  attempt() {
    return this.valid() ? this : null;
  }
  static tryAll(...actions) {
    return actions.find((action) => action instanceof this && action.valid()) || null;
  }
}
class Move extends Action {
  constructor(cell, test) {
    super(cell, test);
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && (view[this.cell].food === 0 || ME.food === 0 || ME.type === QUEEN);
  }
  static many(cells, test) {
    return cells.map((cell) => new this(cell, test));
  }
}
class Paint extends Action {
  constructor(cell, color, test) {
    super(cell, test);
    this.color = color;
  }

  valid() {
    return super.valid() && view[this.cell].color !== this.color && this.color >= 1 && this.color <= 8;
  }
  static many(cells, colors, test) {
    return cells.map((cell, i) => new this(cell, colors[i % colors.length], test));
  }
}
class Spawn extends Action {
  constructor(cell, type, test) {
    super(cell, test);
    this.type = type;
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && view[this.cell].food === 0 && ME.food > 0 && ME.type === QUEEN && this.type >= 1 && this.type <= 4;
  }
  static many(cells, type, test) {
    return cells.map((cell, i) => new this(cell, type, test));
  }
}
class NOP extends Action {
  constructor() {
    super(CENTER);
  }

  valid() {
    return true;
  }
}

class Context {
  apply(func, ...args) {
    const hiddenView = view;
    if (this.viewTranslator) {
      view = this.viewTranslator(hiddenView);
    }

    let output = func(...args);
    if (output instanceof Action && this.outputTranslator) {
      this.outputTranslator(output);
    }

    view = hiddenView;
    return output;
  }
}

class TranslationContext extends Context {
  constructor(translationArray) {
    super();
    this.translationArray = translationArray;
  }

  viewTranslator(oldView) {
    const newView = [];
    for (let i = 0; i < 9; i++) {
      newView.push(oldView[this.translationArray[i]]);
    }
    return newView;
  }

  outputTranslator(out) {
    out.cell = this.translationArray[out.cell];
  }
}
class RotationContext extends TranslationContext {
  constructor(orientation) {
    super(ROTATIONS[orientation]);
    this.orientation = orientation;
  }
}
class OffsetContext extends TranslationContext {
  constructor(centerCell) {
    throw "OffsetContext not implemented";
  }
}
class HorizontalReflectionContext extends TranslationContext {
  constructor() {
    super(HORIZONTAL_FLIP);
  }
}
class VerticalReflectionContext extends TranslationContext {
  constructor() {
    super(VERTICAL_FLIP);
  }
}

class ColorMapContext extends Context {
  constructor(map, unmap) {
    super();
    this.map = map;
    this.unmap = unmap;
  }

  viewTranslator(oldView) {
    return oldView.map((cell) => ({color: this.map[cell.color - 1], food: cell.food, ant: cell.ant}));
  }

  outputTranslator(out) {
    out.color = this.unmap[out.color - 1];
  }
}

class XY {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  static fromTuples(...xyTuples) {
    return xyTuples.map((xy) => new this(xy[0], xy[1]));
  }
}

class WrapProperties {
  constructor(horizontal, vertical, size, wrapOffsets) {
    this.horizontal = !!horizontal;
    this.vertical = !!vertical;
    this.size = size;
    this.wrapOffsets = wrapOffsets || {};
  }
}

class ScoredTest {
  constructor(test, score = 1) {
    this.test = test;
    this.score = score;
  }

  run(cell) {
    return this.test.run(cell) ? this.score : 0;
  }
}

class Environment {
  constructor(tests, wrapping) {
    this.tests = tests.map((test) => test instanceof Test ? new ScoredTest(test) : test);
    this.wrapping = wrapping;
  }

  at(x, y) {
    const w = this.wrapping;
    while ((w.horizontal && (x < 0 || x >= w.size.x)) || (w.vertical && (y < 0 || y >= w.size.y))) {
      if (w.horizontal) {
        if (x < 0) {
          x += w.size.x;
          y += w.wrapOffsets.left || 0;
        } else if (x >= w.size.x) {
          x -= w.size.x;
          y += w.wrapOffsets.right || 0;
        }
      }

      if (w.vertical) {
        if (y < 0) {
          y += w.size.y;
          x += w.wrapOffsets.up || 0;
        } else if (y >= w.size.y) {
          y -= w.size.y;
          x += w.wrapOffsets.down || 0;
        }
      }
    }

    if ((!w.horizontal || (x >= 0 && x < w.size.x)) && (!w.vertical || (y >= 0 || y < w.size.y))) {
      return this.tests[x + y * w.size.x];
    } else {
      return null;
    }
  }
  around(x, y) {
    const arr = [];
    for (let oy = -1; oy <= 1; oy++) {
      for (let ox = -1; ox <= 1; ox++) {
        arr.push(this.at(x + ox, y + oy));
      }
    }
    return arr;
  }

  detect(...positions) {
    return createArray((i) => new RotationContext(i), 4).reduce((best, context) => {
      const next = context.apply(() => {
        return positions.reduce((best, pos, i) => {
          let score = 0;
          const matches = this.around(pos.x, pos.y).map((test, i) => {
            if (test && (test.test instanceof Test)) {
              const result = test.run(i);
              if (result) {
                score += result;
                return true;
              } else {
                return false;
              }
            } else {
              return null;
            }
          });
          if (score > best.score) {
            return {position: pos, positionIndex: i, orientation: context.orientation, environment: this, matches: matches, score: score, confidence: score - best.score};
          } else {
            best.confidence = Math.min(best.score - score, best.confidence);
            return best;
          }
        }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
      });
      if (next.score > best.score) {
        next.confidence = next.score - best.score;
        return next;
      } else {
        best.confidence = Math.min(best.score - next.score, best.confidence);
        return best;
      }
    }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
  }

  static chooseBest(...detectionResults) {
    const r = detectionResults.reduce((best, result, i) => {
      if (result.score > best.score) {
        result.index = i;
        result.confidence = result.score - best.score;
        return result;
      } else {
        best.confidence = Math.min(best.score - result.score, best.confidence);
        return best;
      }
    });
    r.index = r.index || 0;
    return r;
  }
}

class ColoredEnvironment extends Environment {
  constructor(colors, wrapping) {
    super(colors.map((color) => new ColorTest(color)), wrapping);
  }

  getPainter(detectionResult) {
    return new (class Painter {
      constructor(loc) {
        this.pos = loc.position;
        this.matches = loc.matches;
        this.colors = loc.environment.around(this.pos.x, this.pos.y).map((test) => test && test.test instanceof ColorTest ? test.test.color : null);
        this.test = new MatchTest(loc.matches).invert();
        this.orient = loc.orientation;
      }

      paint(...cells) {
        return cells.map((cell) => new Paint(cell, this.colors[cell], this.test));
      }
      cleanup(eraseColor, eraseTargets, ...cells) {
        const eraseQual = this.test.and(new ColorBandTest(eraseTargets));
        return cells.map((cell) => new Paint(cell, eraseColor, eraseQual));
      }
    })(detectionResult);
  }
}

// HIGH-LEVEL LOGIC STARTS HERE //
const PARTNER = 1;

// TODO: Do a 180 when 3 workers are in front of us
function logicOrthogonal(frontC, sideC, backC, backCells, moveCells) {
  const a = [frontC, sideC, backC, backCells, moveCells];
  const f = new FoodTest;
  return Action.tryAll(
    ...Move.many([frontC, sideC], f),
    f.some(backCells) ? new Move(backC) : null,
    ...Move.many(moveCells),
    new NOP
  );
}
function logicDiagonal(adjacentC) {
  return Action.tryAll(...Move.many(adjacentC), new NOP);
}
function logic(partnerTest, partnerOrthC, partnerDiagC, frontC, sideC, backC, backCells, moveCells, adjacentC) {
  function detectEnv(c) {
    return new Environment(createArray((i) => i === c ? partnerTest : undefined, 9), new WrapProperties(false, false, new XY(3, 3), null)).detect(new XY(1, 1));
  }
  const orth = detectEnv(partnerOrthC);
  const diag = detectEnv(partnerDiagC);
  return orth.score === 1 ? new RotationContext(orth.orientation).apply(() => logicOrthogonal(frontC, sideC, backC, backCells, moveCells)) : 
    diag.score === 1 ? new RotationContext(diag.orientation).apply(() => logicDiagonal(adjacentC)) : 
    error("How did we get here?");
}

if (ME.type === QUEEN) {
  const partner = new AntTest(true, PARTNER);
  if (partner.some(DIRECTIONS)) {
    return logic(partner, 5, 8, 2, 1, 7, [0, 3, 6, 7], [2, 7, 1, 8], [5, 7]);
  } else {
    const COLOR = 5;
    const bgTest = new ColorTest(WHITE);
    if (bgTest.run(CENTER)) {
      return new Paint(CENTER, COLOR).attempt() || error("Something went terribly wrong while painting own cell");
    }

    const food = new FoodTest().find(DIRECTIONS);
    if (food !== undefined) {
      return new Move(food);
    }

    const det = new ColoredEnvironment([
      WHITE, WHITE, WHITE, 
      WHITE, undefined, undefined,
      WHITE, undefined, COLOR
    ], new WrapProperties(false, false, new XY(3, 3))).detect(new XY(1, 1));
    return (ME.food > 0 ? Action.tryAll(...Spawn.many(ORTHOGONALS, PARTNER)) : null) ||
      (det.score === 6 ? new RotationContext(det.orientation).apply(() => Action.tryAll(...Move.many([0, 2, 6, 1, 3, 5, 7, 8]))) : null) ||
      Action.tryAll(...Move.many(DIAGONALS_ORTHOGONALS), new NOP);
  }
} else {
  return logic(new AntTest(true, QUEEN), 1, 0, 2, 5, 3, [8, 7, 6, 3], [2, 3, 5, 0], [1, 3]);
}

설명

이것은 내가 아무도 생각하지 않은 매우 간단한 개미입니다 ...

이 개미는 고전적인 접근법으로 1 개의 음식을 모은 후 파트너를 생산합니다. 그 후, 여왕과 파트너는 서로의 위치를 ​​사용하여 가능한 최고 속도 (회 전당 하나의 셀) 로 직선의 대각선으로 이동합니다 . 그들은 어떤 세포도 칠하지 않습니다. 그들은 한 턴에 평균 6 개의 세포를 조사하여 빈 맵에서 게임당180 개의 음식을 그물에 담아 지속적으로 달성했습니다.

버전 2.0 이상이 나왔습니다! 이 항목의 세부 사항을 설명하는 코드에 주석이 있습니다.


변경 로그

버전 1.0

  • 초판

버전 2.0

  • 완전히 개조 된 기동
    • 더 많은 이동 옵션을 위해 대각선 인접성을 활용합니다.
    • 음식 잡기에 대한 변화된 행동
      • 평균 회수율은 변하지 않지만 시스템은 더 강력합니다
      • 하나 이상의 음식이 존재할 때 교착 상태를 방지하여 일관성을 크게 향상시킵니다.
      • 방향 변경 속도 감소
      • 음식 자체를 뒤에서 잡을 수있다
    • 장애물 회피 행동 변경
      • 교착 상태 가능성을 줄이고 일관성을 향상시킵니다.
      • 절대적으로 필요한 경우를 제외하고 U 턴하지 않으며, 평균 총 면적 증가
  • 코드 정리
  • 댓글 추가

버전 2.1

  • 이국적인 교착 상태 해결

버전 2.2

  • 또 다른 이국적인 교착 상태 해결

버전 2.3

  • 적을 피하는 것이 훨씬 더 효과적입니다.

버전 2.3.1

  • 적을 피하는 것이 약간 더 효과적입니다

버전 2.4

  • Formic Framework가 버전 5.0.4 (1.0에서)로 업데이트되었습니다.
  • 리팩토링 된 코드 (버전 2.3.1과 거의 동일한 동작)

버전 2.5

  • Formic Framework가 버전 6.1.10 (5.0.4에서)으로 업데이트되었습니다.
  • 새로운 코딩 표준에 맞게 리팩토링 된 코드 (버전 2.4와 거의 동일한 동작)
  • 제거 된 코드 주석 :(

버전 2.5.0.1

  • 사소한 수정

버전 2.5.0.2

  • 채팅 에서 dzaima 의 도움으로 실격 버그 수정

버전 2.5.0.3

  • 비활성화 된 디버깅

8

트레일 지우개

var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells
if(view[4].ant.type == 5) {
//Queen moves straight to get food
// Color own cell if white
if (view[4].color != 6) { 
    return {cell:4, color:6}
}
var specified = null;
// Otherwise move to a white cell opposite a colored cell
for (i=0; i<4; i++) {
    j = (i+2) % 4
    if (view[orthogonals[i]].color !== 6 &&
        view[orthogonals[j]].color == 6 && !view[orthogonals[i]].ant) {
        specified = {cell:orthogonals[i]}
    } else if (view[4].ant.food < 8 && view[4].ant.food && view[orthogonals[i]].color !== 6 && !view[orthogonals[i]].ant && !view[orthogonals[i]].food && view[orthogonals[i]].color !== 1) {
        //create workers once I encounter a trail
        return {cell:orthogonals[i], type:(view[orthogonals[i]].color%4)+1};
    } else if (view[orthogonals[i]].food) {
        return {cell:orthogonals[i]}
    }
}
if(specified) { return specified; }
// Otherwise move to one of the vertical or horizontal cells if not occupied
for (i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i};
    }
}

// Otherwise don't move at all
return {cell:4};
}
//workers erase their trails
//Follow the trail to erase
var move, color, enemyAnt = false;
var nearbyColoredCells = 0;
if(view[4].color != 1){
   color =  {cell:4, color:1}
}
for(i=0;i<9;i++) {
    if(i != 4 && view[i].color != 1 && !view[i].ant && (!view[4].ant.food || !view[i].food) && (!move || (view[i].color % 4 + 1) == view[4].type || (view[move.cell].color == 6 && view[i].color != 6))) {
        move = {cell:i}
    }
    if(view[i].ant && view[i].ant.friend && view[i].ant.type == 5){
       return {cell:4}
    }
    if(i != 4 && view[i].color != 1 && view[i].color != 6){
        nearbyColoredCells += 1;
    }
    if(view[i].ant && !view[i].ant.friend) {
         enemyAnt = i;
    }
}
if(nearbyColoredCells <= 1 || enemyAnt > 1) {
    // Either I'm following a standard trail or there are enemy workers; possibly decolor own cell and move
    if(color && (!move || !enemyAnt)) { return color; }
    if(move) { return move; }
} else if (nearbyColoredCells > 1){
   for (i = 0; i < 9; i++){
       if(view[i].color != 1){ return {cell:i, color:1} }
   }
}
// uh-oh, our trail ended or we got lost -- random walk
// find a safe place to move
for (i=0;i<9;i+=1) {
    if (!view[i].ant && (!view[4].ant.food || !view[i].food)) {
       return {cell:i}
    }
}
return {cell:4}

이 개미는 음식을 찾는 데 적당하지만 (로마 개미 나 법의학 개미만큼 좋지는 않지만) 다른 개미를 혼동 시키려고합니다. 그것은 교차하는 색의 길을 만날 때마다 흔적을 지우는 유일한 목적을 가진 작업자를 만들어서 그렇게합니다. 트레일 끝에 도달 한 작업자는 다른 트레일을 찾을 때까지 쓸데없이 무작위로 걸어갑니다. 음식을 보존하고 더 잘하기 위해,이 개미는 음식을 8 개 먹으면 더 많은 노동자를 생산하지 않는 전략으로 전환 할 것입니다. 모두 사용하십시오.


1
사보타주! the 로마인들은 당신에게 무엇을 했습니까?
Dave

이 항목은 블랙홀을 엉망으로 만드는 재미를 많이 가지고 있습니다 ...
Frenzy Li

2
@Dave 그들은이 도전에 경쟁 항목을 제출했습니다 ...
pppery

2
야,이 플레이어는 때때로 로마 개미에 의해 혼동되어 음식을 모두 낭비합니다
pppery

2
두 번째 업데이트 : 더 이상 음식을 처음에 저장하지 않고 나중에 방해하지 않고 음식을 수집하기 시작합니다
pppery

8

하이퍼 파

모든 답변에는 Formic Functions Framework 형식의 유사한 하위 수준 논리가 포함됩니다. "높은 수준의 논리가 여기에서 시작됨"은 프레임 워크 코드의 끝을 나타냅니다.

 //  FORMIC FRAMEWORK  //
// Version 6.1.10     //
const WHITE = 1;
const QUEEN = 5;
const CENTER = 4;
const HERE = view[CENTER];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const ROTATIONS = [
  [0, 1, 2,
   3, 4, 5,
   6, 7, 8],

  [6, 3, 0,
   7, 4, 1,
   8, 5, 2],

  [8, 7, 6,
   5, 4, 3,
   2, 1, 0],

  [2, 5, 8,
   1, 4, 7,
   0, 3, 6]
];
const NEIGHBORS = [
  [1, 4, 3],
  [2, 5, 4, 3, 0],
  [5, 4, 1],
  [0, 1, 4, 7, 6],
  [0, 1, 2, 5, 8, 7, 6, 3],
  [8, 7, 4, 1, 2],
  [3, 4, 7],
  [6, 3, 4, 5, 8],
  [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = true;
function dump() {
  if (DEBUG_MODE) {
    throw "dump() not implemented";
  }
}
function log(...args) {
  if (DEBUG_MODE) {
    console.log(...args);
  }
}
function error(...args) {
  log("Transformed view state:", view);
  log(...args);
  throw "A critical error has occurred!";
}

function createArray(func, length) {
  const arr = [];
  for (let i = 0; i < length; i++) {
    arr.push(func(i, arr));
  }
  return arr;
}

class Test {
  run(cell) {
    error("No run method defined for this instance of Test:", this);
  }
  find(cells = CELLS) {
    return cells.find((c) => this.run(c));
  }
  findIndex(cells = CELLS) {
    return cells.findIndex((c) => this.run(c));
  }
  filter(cells = CELLS) {
    return cells.filter((c) => this.run(c));
  }
  every(cells = CELLS) {
    return cells.every((c) => this.run(c));
  }
  some(cells = CELLS) {
    return cells.some((c) => this.run(c));
  }
  count(cells = CELLS) {
    return this.filter(cells).length;
  }
  invert() {
    return new InverseTest(this);
  }
  and(test) {
    return new EveryTest(this, test);
  }
  or(test) {
    return new SomeTest(this, test);
  }
}

class InverseTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return !this.test.run(cell);
  }
  invert() {
    return this.test;
  }
}

class CombinedTest extends Test {
  constructor(...tests) {
    super();
    this.tests = tests;
  }
  append(test) {
    this.tests.push(test);
    return this;
  }
}
class EveryTest extends CombinedTest {
  run(cell) {
    return this.tests.every((test) => test.run(cell));
  }
  and(test) {
    return this.append(test);
  }
}
class SomeTest extends CombinedTest {
  run(cell) {
    return this.tests.some((test) => test.run(cell));
  }
  or(test) {
    return this.append(test);
  }
}

class ColorTest extends Test {
  constructor(color) {
    super();
    this.color = color;
  }
  run(cell) {
    return view[cell].color === this.color;
  }
}
class ColorBandTest extends SomeTest {
  constructor(colorBand) {
    super(...colorBand.map((color) => new ColorTest(color)));
  }
}

class FoodTest extends Test {
  constructor(hasFood = true) {
    super();
    this.food = hasFood ? 1 : 0;
  }
  run(cell) {
    return view[cell].food === this.food;
  }
}

class AntTest extends Test {
  constructor(friend, type, food) {
    super();
    this.friend = friend;
    this.type = type;
    this.food = food;
  }
  run(cell) {
    const ant = view[cell].ant;
    return ant !== null && (this.type === undefined || ant.type === this.type) && (this.friend === undefined || ant.friend === this.friend) && (this.food === undefined || (this.food ? ant.food > 0 : ant.food === 0));
  }
}

class NeighborTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return this.test.some(NEIGHBORS[cell]);
  }
}

class MatchTest extends Test {
  constructor(matches) {
    super();
    this.matches = matches;
  }
  run(cell) {
    return this.matches[cell];
  }
}

class CustomTest extends Test {
  constructor(func, ...args) {
    super();
    this.func = func;
    this.args = args;
  }
  run(cell) {
    return this.func(cell, ...this.args);
  }
}

class Action {
  constructor(cell, test) {
    this.cell = cell;
    this.test = test;
  }

  valid() {
    return this.cell >= 0 && this.cell < 9 && (!this.test || this.test.run(this.cell));
  }
  attempt() {
    return this.valid() ? this : null;
  }
  static tryAll(...actions) {
    return actions.find((action) => action instanceof this && action.valid()) || null;
  }
}
class Move extends Action {
  constructor(cell, test) {
    super(cell, test);
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && (view[this.cell].food === 0 || ME.food === 0 || ME.type === QUEEN);
  }
  static many(cells, test) {
    return cells.map((cell) => new this(cell, test));
  }
}
class Paint extends Action {
  constructor(cell, color, test) {
    super(cell, test);
    this.color = color;
  }

  valid() {
    return super.valid() && view[this.cell].color !== this.color && this.color >= 1 && this.color <= 8;
  }
  static many(cells, colors, test) {
    return cells.map((cell, i) => new this(cell, colors[i % colors.length], test));
  }
}
class Spawn extends Action {
  constructor(cell, type, test) {
    super(cell, test);
    this.type = type;
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && view[this.cell].food === 0 && ME.food > 0 && ME.type === QUEEN && this.type >= 1 && this.type <= 4;
  }
  static many(cells, type, test) {
    return cells.map((cell, i) => new this(cell, type, test));
  }
}
class NOP extends Action {
  constructor() {
    super(CENTER);
  }

  valid() {
    return true;
  }
}

class Context {
  apply(func, ...args) {
    const hiddenView = view;
    if (this.viewTranslator) {
      view = this.viewTranslator(hiddenView);
    }

    let output = func(...args);
    if (output instanceof Action && this.outputTranslator) {
      this.outputTranslator(output);
    }

    view = hiddenView;
    return output;
  }
}

class TranslationContext extends Context {
  constructor(translationArray) {
    super();
    this.translationArray = translationArray;
  }

  viewTranslator(oldView) {
    const newView = [];
    for (let i = 0; i < 9; i++) {
      newView.push(oldView[this.translationArray[i]]);
    }
    return newView;
  }

  outputTranslator(out) {
    out.cell = this.translationArray[out.cell];
  }
}
class RotationContext extends TranslationContext {
  constructor(orientation) {
    super(ROTATIONS[orientation]);
    this.orientation = orientation;
  }
}
class OffsetContext extends TranslationContext {
  constructor(centerCell) {
    throw "OffsetContext not implemented";
  }
}
class HorizontalReflectionContext extends TranslationContext {
  constructor() {
    super(HORIZONTAL_FLIP);
  }
}
class VerticalReflectionContext extends TranslationContext {
  constructor() {
    super(VERTICAL_FLIP);
  }
}

class ColorMapContext extends Context {
  constructor(map, unmap) {
    super();
    this.map = map;
    this.unmap = unmap;
  }

  viewTranslator(oldView) {
    return oldView.map((cell) => ({color: this.map[cell.color - 1], food: cell.food, ant: cell.ant}));
  }

  outputTranslator(out) {
    out.color = this.unmap[out.color - 1];
  }
}

class XY {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  static fromTuples(...xyTuples) {
    return xyTuples.map((xy) => new this(xy[0], xy[1]));
  }
}

class WrapProperties {
  constructor(horizontal, vertical, size, wrapOffsets) {
    this.horizontal = !!horizontal;
    this.vertical = !!vertical;
    this.size = size;
    this.wrapOffsets = wrapOffsets || {};
  }
}

class ScoredTest {
  constructor(test, score = 1) {
    this.test = test;
    this.score = score;
  }

  run(cell) {
    return this.test.run(cell) ? this.score : 0;
  }
}

class Environment {
  constructor(tests, wrapping) {
    this.tests = tests.map((test) => test instanceof Test ? new ScoredTest(test) : test);
    this.wrapping = wrapping;
  }

  at(x, y) {
    const w = this.wrapping;
    while ((w.horizontal && (x < 0 || x >= w.size.x)) || (w.vertical && (y < 0 || y >= w.size.y))) {
      if (w.horizontal) {
        if (x < 0) {
          x += w.size.x;
          y += w.wrapOffsets.left || 0;
        } else if (x >= w.size.x) {
          x -= w.size.x;
          y += w.wrapOffsets.right || 0;
        }
      }

      if (w.vertical) {
        if (y < 0) {
          y += w.size.y;
          x += w.wrapOffsets.up || 0;
        } else if (y >= w.size.y) {
          y -= w.size.y;
          x += w.wrapOffsets.down || 0;
        }
      }
    }

    if ((!w.horizontal || (x >= 0 && x < w.size.x)) && (!w.vertical || (y >= 0 || y < w.size.y))) {
      return this.tests[x + y * w.size.x];
    } else {
      return null;
    }
  }
  around(x, y) {
    const arr = [];
    for (let oy = -1; oy <= 1; oy++) {
      for (let ox = -1; ox <= 1; ox++) {
        arr.push(this.at(x + ox, y + oy));
      }
    }
    return arr;
  }

  detect(...positions) {
    return createArray((i) => new RotationContext(i), 4).reduce((best, context) => {
      const next = context.apply(() => {
        return positions.reduce((best, pos, i) => {
          let score = 0;
          const matches = this.around(pos.x, pos.y).map((test, i) => {
            if (test && (test.test instanceof Test)) {
              const result = test.run(i);
              if (result) {
                score += result;
                return true;
              } else {
                return false;
              }
            } else {
              return null;
            }
          });
          if (score > best.score) {
            return {position: pos, positionIndex: i, orientation: context.orientation, environment: this, matches: matches, score: score, confidence: score - best.score};
          } else {
            best.confidence = Math.min(best.score - score, best.confidence);
            return best;
          }
        }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
      });
      if (next.score > best.score) {
        next.confidence = next.score - best.score;
        return next;
      } else {
        best.confidence = Math.min(best.score - next.score, best.confidence);
        return best;
      }
    }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
  }

  static chooseBest(...detectionResults) {
    const r = detectionResults.reduce((best, result, i) => {
      if (result.score > best.score) {
        result.index = i;
        result.confidence = result.score - best.score;
        return result;
      } else {
        best.confidence = Math.min(best.score - result.score, best.confidence);
        return best;
      }
    });
    r.index = r.index || 0;
    return r;
  }
}

class ColoredEnvironment extends Environment {
  constructor(colors, wrapping) {
    super(colors.map((color) => new ColorTest(color)), wrapping);
  }

  getPainter(detectionResult) {
    return new (class Painter {
      constructor(loc) {
        this.pos = loc.position;
        this.matches = loc.matches;
        this.colors = loc.environment.around(this.pos.x, this.pos.y).map((test) => test && test.test instanceof ColorTest ? test.test.color : null);
        this.test = new MatchTest(loc.matches).invert();
        this.orient = loc.orientation;
      }

      paint(...cells) {
        return cells.map((cell) => new Paint(cell, this.colors[cell], this.test));
      }
      cleanup(eraseColor, eraseTargets, ...cells) {
        const eraseQual = this.test.and(new ColorBandTest(eraseTargets));
        return cells.map((cell) => new Paint(cell, eraseColor, eraseQual));
      }
    })(detectionResult);
  }
}

// HIGH-LEVEL LOGIC STARTS HERE //
// TODO:
// - more food checkpoints (no disadvantages because it's illogical for WFW to "premanently lose" workers)
// - randomly shifting 1 up (5% chance? watch out for hoarding stealing your randomness!)
// - randomly skip painting a tiny bit of local cells (prevent deadlock against ants outside of view)
// - escape routine when situation is dire (many workers near the queen/partner)

const COLOR_BAND = [4, 7, 3, 2, 8];

const PARTNER = 2;
const WORKER = 1;

const START_FOOD = 6;
const MIN_CONFIDENCE = 2;

const PATTERN = new ColoredEnvironment(COLOR_BAND, new WrapProperties(true, true, new XY(COLOR_BAND.length, 1), {up: 2, down: -2})).detect(...createArray((i) => new XY(i, 0), COLOR_BAND.length));

function checkpoint(val, tolerance) {
  return ME.food >= val - tolerance && ME.food <= val;
}
function shouldSpawn() {
  return PATTERN.orientation === 0 && PATTERN.positionIndex % 3 === 0 &&
    ME.food < 400 &&
    (ME.food < 75 || PATTERN.positionIndex === 0) && 
    !checkpoint(300, 4) &&
    !checkpoint(200, 5) &&
    !checkpoint(160, 3) &&
    !checkpoint(130, 2) &&
    !checkpoint(100, 2) &&
    !checkpoint(75, 2) &&
    !checkpoint(50, 2) &&
    !checkpoint(35, 1) &&
    !checkpoint(20, 1) &&
    !checkpoint(10, 0);
}

function lightspeed() {
  // TODO: Do a 180 when 3 workers are in front of us
  function logicOrthogonal(frontC, sideC, backC, backCells, moveCells) {
    const a = [frontC, sideC, backC, backCells, moveCells];
    const f = new FoodTest;
    return Action.tryAll(
      ...Move.many([frontC, sideC], f),
      f.some(backCells) ? new Move(backC) : null,
      ...Move.many(moveCells),
      new NOP
    );
  }
  function logicDiagonal(adjacentC) {
    return Action.tryAll(...Move.many(adjacentC), new NOP);
  }
  function logic(partnerTest, partnerOrthC, partnerDiagC, frontC, sideC, backC, backCells, moveCells, adjacentC) {
    function detectEnv(c) {
      return new Environment(createArray((i) => i === c ? partnerTest : undefined, 9), new WrapProperties(false, false, new XY(3, 3), null)).detect(new XY(1, 1));
    }
    const orth = detectEnv(partnerOrthC);
    const diag = detectEnv(partnerDiagC);
    return orth.score === 1 ? new RotationContext(orth.orientation).apply(() => logicOrthogonal(frontC, sideC, backC, backCells, moveCells)) : 
      diag.score === 1 ? new RotationContext(diag.orientation).apply(() => logicDiagonal(adjacentC)) : 
      error("How did we get here?");
  }

  if (ME.type === QUEEN) {
    const partner = new AntTest(true, PARTNER);
    if (partner.some(DIRECTIONS)) {
      return logic(partner, 5, 8, 2, 1, 7, [0, 3, 6, 7], [2, 7, 1, 8], [5, 7]);
    } else {
      const COLOR = 5;
      const bgTest = new ColorTest(WHITE);
      if (bgTest.run(CENTER)) {
        return new Paint(CENTER, COLOR).attempt() || error("Something went terribly wrong while painting own cell");
      }

      const food = new FoodTest().find(DIRECTIONS);
      if (food !== undefined) {
        return new Move(food);
      }

      const det = new ColoredEnvironment([
        WHITE, WHITE, WHITE, 
        WHITE, undefined, undefined,
        WHITE, undefined, COLOR
      ], new WrapProperties(false, false, new XY(3, 3))).detect(new XY(1, 1));
      return (ME.food > 0 ? Action.tryAll(...Spawn.many(ORTHOGONALS, PARTNER)) : null) ||
        (det.score === 6 ? new RotationContext(det.orientation).apply(() => Action.tryAll(...Move.many([0, 2, 6, 1, 3, 5, 7, 8]))) : null) ||
        Action.tryAll(...Move.many(DIAGONALS_ORTHOGONALS), new NOP);
    }
  } else {
    return logic(new AntTest(true, QUEEN), 1, 0, 2, 5, 3, [8, 7, 6, 3], [2, 3, 5, 0], [1, 3]);
  }
}

function queen() {
  const partnerTest = new AntTest(true, PARTNER);
  if (PATTERN.confidence < MIN_CONFIDENCE && (ME.food < START_FOOD || partnerTest.some(DIAGONALS))) return lightspeed();
  return new RotationContext(PATTERN.orientation).apply(() => {
    const partnerCell = new AntTest(true, PARTNER).find(DIRECTIONS);
    const p = PATTERN.environment.getPainter(PATTERN);
    const e = new AntTest(false);
    const enemy = e.some(DIRECTIONS);
    return Action.tryAll(
      ...!PATTERN.matches[8] ? [
        ...!enemy ? [...p.paint(7, 4, 5, 1, 2), ...shouldSpawn() && PATTERN.score === 8 ? Spawn.many([0, 2], WORKER) : []] : [],
        ...partnerCell === 1 ? Move.many(e.run(5) ? [0, 2] : PATTERN.orientation === 1 && PATTERN.positionIndex % 3 === 1 ? [2, 0, 5] : [5, 2, 0]) : 
          partnerCell === 0 ? Move.many(e.run(1) ? [3] : enemy ? [1, 3] : []) :
          partnerCell === 2 ? Move.many(e.run(1) ? [5] : []) :
          []
      ] : [
        ...!enemy ? p.paint(8, 7, 6, 5, 4, 3, 2, 1, 0) : [],
        ...Move.many(partnerCell === 1 ? [2, 0] : partnerCell === 0 ? [1, 3] : partnerCell === 2 && e.run(1) ? [5] : [])
      ],
      new NOP
    )
  });
}
function partner() {
  const queenTest = new AntTest(true, QUEEN)
  const queenCell = queenTest.find(DIRECTIONS);
  if (queenCell === undefined) {
    return new NOP; // TODO: What do we do if we've lost our queen?
  }
  if (PATTERN.confidence < MIN_CONFIDENCE && (view[queenCell].ant.food < START_FOOD || DIAGONALS.includes(queenCell))) return lightspeed();
  return PATTERN.confidence >= MIN_CONFIDENCE ? new RotationContext(PATTERN.orientation).apply(() => {
    const queenCell = queenTest.find(DIRECTIONS);
    const e = new AntTest(false);
    const enemy = e.some(DIRECTIONS);
    return Action.tryAll(
      ...!enemy ? PATTERN.environment.getPainter(PATTERN).paint(...CELLS) : [],
      ...Move.many([
        [1],
        [0, 2],
        [1],
        [0, 1],
        [], // Queen can't be on cell 4 - I'm here, after all!
        [2, 1],
        [3],
        [],
        [5]
      ][queenCell]),
      new NOP
    )
  }) : new NOP;
}
function worker() {
  const m = new MatchTest(PATTERN.matches);
  const n = m.invert();
  const u = new AntTest(true, WORKER, false);
  const l = new AntTest(true, WORKER, true);
  const q = new AntTest(true, QUEEN);
  const pt = new AntTest(true, PARTNER);
  const p = PATTERN.environment.getPainter(PATTERN);
  return new RotationContext(PATTERN.orientation).apply(() => { // TODO: Unique (random?) behavior when confidence low
    if (ME.food === 0) {
      const f = new FoodTest();
      const count = n.count([6, 7, 8]);
      return Action.tryAll(
        ...PATTERN.confidence >= 2 ? p.paint(4, 0, 1, 2) : [],
        //...p.cleanup(WHITE, COLOR_BAND, ...CELLS),
        ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food], food), new Move(food)] : [])(f.find(DIRECTIONS)),
        ...q.or(pt).some(DIRECTIONS) || u.some([6, 7, 8, 5, 2]) ? Move.many([0, 1, 3], m) : [],
        ...count > 1 ? p.paint(...[6, 7, 8]) : [],
        ...count === 1 ? [...p.paint(...[3, 5]), ...Move.many([7, 8, 6, 3], m)] : [],
        /*n.run(6) ? new Move(3, m) : null,
        ...n.run(7) ? Move.many([6, 3], m) : [],
        n.run(8) ? new Move(7, m) : null,*/
        n.run(5) ? new Move(5) : null,
        ...Move.many([2, 1, 0, 3], m),
        new NOP
        /*
        ...(PATTERN.confidence >= 2 ? [...(PATTERN.score < 8 || new AntTest(false).some(DIRECTIONS) ? p.paint(4, 3, 0, 1, 2, 5) : []), ...p.cleanup(WHITE, COLOR_BAND, ...CELLS)] : []),
        ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food]), new Move(food)] : [])(f.find(DIRECTIONS)), ...(
          w ? Move.many([1, 0, 2]) :
          m.some([4, 3]) ? p.paint(4, 3) :
          m.some([0, 1, 2]) ? Move.many([1, 5]) :
          m.run(6) ? [new Move(3)] :
          m.run(7) ? Move.many([6, 3]) :
          m.run(8) ? [new Move(7)] :
          m.run(5) ? Move.many([5, 7]) :
          Move.many([2, 1, 5])
        )
        new NOP*/
      );
    } else {
      return Action.tryAll(
        //...Move.many(new AntTest(true, WORKER).some([2, 5, 8, 7]) || PATTERN.score < 9 ? [8, 7, 6, 3] : [5, 8, 2], m.invert()),
        ...((test) => createArray((i) => new Move(CLOCKWISE_DIRECTIONS[(6 - i) % 8], test), 5))(new CustomTest((cell, moveTest, blockTest) => {
          const i = CLOCKWISE_DIRECTIONS.findIndex((c) => c === cell);
          return moveTest.run(CLOCKWISE_DIRECTIONS[i]) && blockTest.run(CLOCKWISE_DIRECTIONS[((i - 1) + 8) % 8]);
        }, m, n.or(new AntTest().and(l.invert())))),
        ...Move.many([2, 5, 1, 8], m),
        //...Move.many([...(PATTERN.score === 9 && !new AntTest(true, WORKER).some(DIRECTIONS) ? [2] : []), 5, 8, 7, 6, 3], m),
        new NOP
      );
    }
  });
}

switch (ME.type) {
  case QUEEN: {
    return queen();
  }
  case PARTNER: {
    return partner();
  }
  case WORKER: {
    return worker();
  }
}

시간 압력 때문에이 항목에 대한 모든 설명을 일시적으로 제거했습니다. 나중에이 주요 업데이트에 대한 자세한 설명을 추가하겠습니다.


변경 로그

버전 1.0

  • 초판

버전 2.0

  • 고속도로를 초고주파로 교체

버전 2.0.1

  • 핫픽스 보딩 메커니즘

이것은 아름답게보기 시작하고
겁나게

1
도로에 대한 뱀파이어 칙령을 제정 할 시간입니다.
Draco18s

그리고 @ Draco18s에서 시간이 지남에 따라 뱀파이어에게 더 많은 음식을 공급할 것입니다-많은 개선이 필요합니다.
Alion

3
첫 번째 항목은 표준 게임 시간 내에 보드를 완전히 차지할 수있는 것을 보았습니다. 매우 인상적.
Dave

7

로마 개미 Mk.2

모든 대답은 동일한 하위 수준 도우미 기능 집합을 공유합니다. 이 답변과 관련된 코드를 보려면 "고수준 논리가 여기서 시작됩니다"를 검색하십시오.

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var QUEEN_COL = colour_band(generate_band(3, 3));
var WORKER_COL = colour_band(generate_band(6, 3));
var AVOID_COL = colour_band([2]);
var INVERT_COL = colour_band([WHITE, 2]);

var MIN_FOOD = 5;
var MAX_WORKER_FOOD = 10;

function decide() {
  var me = view[CENTRE].ant;
  var queen = me.type === QUEEN;

  if(queen && me.food > MIN_FOOD && me.food < MAX_WORKER_FOOD) {
    var m = try_all_cells((i) => {
      if(view[i].food && !foe_near(i)) {
        // Try to spawn a worker next to the food;
        // the worker will pick up the food on the next turn
        return try_all_cells_near(i, (j) => ({cell: j, type: 1}));
      }
    }, true);
    if(sanity_check(m)) {
      return m;
    }
  }

  if(!queen && me.food) {
    return best_of([
      // Look for queen
      follow_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT, DIR_FORWARDS),
      latch_to_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT),

      // Failed to find queen's trail; try following worker trails backwards
      follow_dotted_path.bind(null, WORKER_COL, SIDE_RIGHT, DIR_REVERSE),
      latch_to_dotted_path.bind(null, WORKER_COL, SIDE_RIGHT),

      // Failed to find any trail; cover ground as quickly as possible
      fast_diagonal.bind(null, AVOID_COL)
    ]);
  }

  var myCol = queen ? QUEEN_COL : WORKER_COL;
  return best_of([
    grab_nearby_food,

    // Disperse workers away from queen
    !queen && escape_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT, WORKER_COL),

    // Follow our own path
    follow_dotted_path.bind(null, myCol, SIDE_RIGHT, DIR_FORWARDS),

    // If our path looks suspicious, it could have wrapped; try to escape it
    escape_dotted_path.bind(null, myCol, SIDE_RIGHT),

    // Explore
    // Laying a path causes us to move at 2/3 c, so workers can catch up.
    lay_dotted_path.bind(null, myCol, SIDE_RIGHT, QUEEN_COL),
    start_dotted_path.bind(null, myCol, SIDE_RIGHT, QUEEN_COL),

    // Fall-back to white dots if we're inside a colour block
    lay_dotted_path.bind(null, myCol, SIDE_RIGHT, INVERT_COL),
    start_dotted_path.bind(null, myCol, SIDE_RIGHT, INVERT_COL),

    // Stuck for some reason; try to escape
    fast_diagonal.bind(null, AVOID_COL)
  ]);
}

return play_safe([
  decide,

  // No valid moves; try to find *anywhere* we can go.
  go_anywhere,

  // Try changing a nearby cell's colour for the heck of it.
  {cell: 1, color: view[1].color % 8 + 1}
]);

로마 개미는 길을 곧고 빠르게 건설하는 것을 좋아합니다. 그들은 도로를 점선으로 만들었 기 때문에 빛의 2/3 속도로 움직일 수 있습니다! 그들의 도로는 또한 자전거를 타는 색상을 사용하여 도로를 앞뒤로 따라 가는지 여부를 알 수 있으며 근로자 개미는 여왕과 다른 색상 세트를 사용합니다 (여왕이 당황스럽지 않은 양을 가진 후에는 노동자가 생성되기 시작합니다) 음식 가능). 즉, 개미가 음식을 찾으면 자신의 길을 뒤로 추적 한 다음 여왕의 길을 앞으로 추적하여 음식을 반환 할 수 있습니다 (개미가 빛의 속도로 움직이는 경로를 추적하는 동안).

언제든지 3x3 격자를 볼 수 있고 자신의 방향을 모르더라도 개미가 어떻게 점선을 따라갈 수 있는지 궁금해하는 경우 : 실제 이동 경로가 아니라 오른쪽으로 선을 그립니다. 예를 들어, 개미가 북쪽으로 채워진 정사각형을 보게되면 경로가 그 위에 있어야한다는 것을 알고 있습니다. 이는 여행 방향이 서쪽이어야한다는 것을 의미합니다 (오른쪽에 경로를 유지). 개미가 북동쪽으로 채워진 사각형을 보지만 북동쪽이나 남동쪽으로는 보이지 않는 경우에는 선의 끝을지나 쳐야합니다. 따라서 셀을 북서쪽으로 페인트하고 서쪽으로 여행합니다. 일단 음식이 발견되면 방향 전환에 더 많은 합병증이 있지만 그것이 핵심입니다.

언급 할 가치가있는 또 다른 점은 일개미가 음식을 볼 때 집으로 돌아가는 방법에 대해 생각하지 않고 음식을 잡을 수있는 기회에 뛰어 들게된다는 것입니다. 따라서 개미가 음식을 운반하는 동안 길을 잃은 경우 행동을 무작위로 걷기 쉬운 패턴으로 전환하여 걸음 걸이를 피하기 위해 노란색 흔적을 남겨 둡니다. 이것은 개미가 흔적을 재발견하는 데 도움이되고 그렇지 않으면 발생할 수있는 무한 루프의 일부를 피할 수있는 충분한 무작위성을 도입합니다.

그것은 놀랍게도 수행되지 않으며 개미는 자신의 발자취를 다시 추적하는 습관을 가지고 있습니다 (그들이 따르는 경로가 오래된 경로인지 또는 진행중인 경로인지 알 수 없을 정도로 바보입니다. 때때로 무한 루프가 발생합니다.

마지막으로, 모든 출력에 적용되는 온 전성 검사 방법이 있습니다 (실제로 실격되지 않음).


업데이트 된 버전은 빠른 대각선 이동을 위해 무작위 보행을 전환하고, 많은 버그를 수정하며, 큰 개미가 큰 지역에 갇힌 개미가 있으면 흰색 도로를 이용하여 걷는 시도를 추가합니다. 높은 수준의 생각 / 낮은 수준의 기능 분리를 사용하도록 변환하는 동안 대부분의 버그가 발견되었습니다.


( 베타 에있는 동안 준비한 것이 있습니다 )
Dave

대략적인 크기의 순서를 위해 : 방금 이것을 실행하여 30 개의 음식 + 6 명의 작업자 개미를 얻었습니다. 그것은 내가 개발하는 동안 본 숫자와 일치합니다.
Dave

50 %의 속도 향상을 위해 도로에 공백을 남기는 깔끔한 트릭입니다. 또한 처음에는 도로가 잘 보이지 않는다는 것을 의미합니다. 개미를 찾는 데 시간이 좀 걸렸습니다 ...하지만 특히 노동자가 돌아 오기 시작하면 예제 플레이어보다 쉽게 ​​뛰어납니다. 일부 근로자는 결국 노란색과 흰색 바둑판 패턴으로 확장됩니다. 계획의 일부인지 확실하지 않습니까?
trichoplax

1
@trichoplax 죄송합니다; 나는 그것을 설명에 넣는 것을 잊었다 (그들이 잊어 버렸다!). 설명을 업데이트했습니다. 한마디로 : 그것은 계획의 일부이지만 훌륭한 계획은 아닙니다.
Dave

좋은 설명!
trichoplax

7

모노레일

여전히 진행중인 작업이지만, 달리 끝내기 전에 경쟁이 끝날 것이라는 편집증 때문에 지금 무언가를 밀어 내고 싶습니다.

var c0=5 //red
var c1=4 //cyan
var c2=6 //green
var c3=3 //magenta
var c4=7 //blue
var c5=8 //black
var c6=2 //yellow
var cN=1 //white

var ws=4 //support
var wb=3 //bodyguard
var wg=1 //gather
var wq=5 //queen

var v=[[0, 1, 2, 3, 4, 5, 6, 7, 8],
       [8, 7, 6, 5, 4, 3, 2, 1, 0],
       [6, 3, 0, 7, 4, 1, 8, 5, 2],
       [2, 5, 8, 1, 4, 7, 0, 3, 6]]

var x1=[0,2,6,8]
var x2=[8,6,2,0]

var r1=[1,7,3,5]
var r2=[5,3,7,1]

switch(view[4].ant.type)
{
 case 5: return queen()
 case 4: return support()
 case 3: return bodyguard()
 case 1: return gather()
 default: return {cell:4}
}

function queen()
{
 if(fAlly(ws)<0)
 {
  if(view[4].color==c1&&view[4].ant.food>0)
  {
   var o=findOrient(c1,c2,c3)
   if(sOpen(v[o][7])) return {cell:v[o][7],type:ws}
   return doThing()
  }
  else if(view[4].color==c0&&view[4].ant.food>=6)
  {
   var o=findOrient(c1,c2,c3)
   if(view[v[o][1]].color!=c1) return {cell:v[o][1],color:c1}
   if(view[v[o][0]].color!=c2) return {cell:v[o][0],color:c2}
   if(view[v[o][2]].color!=c3) return {cell:v[o][2],color:c3}
   if(sOpen(v[o][7])) return {cell:v[o][7],type:ws}
  }
  return wander(c0)
 }
 else
 {
  if(view[4].color==c0&&view[4].ant.food<7)
  {
   if(view[4].ant.food >=5)
   {
    var o=findOrient(c1,c2,c3)
    if(sOpen(v[o][1])) return {cell:v[o][1],type:wb}
    if(sOpen(v[o][0])) return {cell:v[o][0],type:wb}
    if(sOpen(v[o][2])) return {cell:v[o][2],type:wb}
   }
   if(view[4].ant.food>0)
   {
    var op=fOpen()
    if(op>=0) return {cell:op,type:wg}
   }
  }
  return doThing()
 }
}

function doThing()
{
 if(view[4].color!=c1) return {cell:4,color:c1}
 var o=findOrient(c1,c2,c3)
 if(view[4].ant.food>0&&fAlly(wg)>=0&&o==0)
 {
  var op=fOpen()
  if(op>=0) return {cell:op,type:wg}
 }
 if(view[v[o][1]].color!=c1&&pootis(v[o][1])) return {cell:v[o][1],color:c1}
 if(view[v[o][0]].color!=c2&&pootis(v[o][0])) return {cell:v[o][0],color:c2}
 if(view[v[o][2]].color!=c3&&pootis(v[o][2])) return {cell:v[o][2],color:c3}
 if(mOpen(v[o][1])) return {cell:v[o][1]}
 if(view[v[o][3]].color!=c2&&pootis(v[o][3])) return {cell:v[o][3],color:c2}
 if(view[v[o][5]].color!=c3&&pootis(v[o][5])) return {cell:v[o][5],color:c3}
 if(view[v[o][6]].color!=c2&&pootis(v[o][6])) return {cell:v[o][6],color:c2}
 if(view[v[o][8]].color!=c3&&pootis(v[o][8])) return {cell:v[o][8],color:c3}
 if(view[v[o][7]].color!=c1&&pootis(v[o][7])) return {cell:v[o][7],color:c1}
 return {cell:4}
}

function support()
{
 var o = findOrient(c1,c2,c3)
 var p = fAlly(wq)

 switch(p)
 {
  case v[o][0]:
   //if(mOpen(v[o][3])) return {cell:v[o][3]}
   //if(mOpen(v[o][1])) return {cell:v[o][1]}
   break
  case v[o][1]:
   //if(view[v[o][0]].food&&mOpen([v[o][0]])) return {cell:v[o][0]}
   //if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
   break
  case v[o][2]:
   //if(mOpen(v[o][5])) return {cell:v[o][5]}
   //if(mOpen(v[o][1])) return {cell:v[o][1]}
   break
  case v[o][3]:
   //if(mOpen(v[o][6])) return {cell:v[o][6]}
   break
  case v[o][5]:
   //if(mOpen(v[o][8])) return {cell:v[o][8]}
   break
  case v[o][6]: break
  case v[o][7]: break
  case v[o][8]: break
  default:
   if(sOpen(v[o][1])) return {cell:v[o][1]}
   break
 }
 return {cell:4}
}

function bodyguard()
{
 var o=0
 switch(view[4].color)
 {
  case c1: o=findOrient(c1,c2,c3);break
  case c2: o=findOrient(c2,c6,c1);break
  case c3: o=findOrient(c3,c1,c6);break
  default: return {cell:4}
 }
 var p = fAlly(wq)
 if(view[4].ant.food>0)
 {
  switch(p)
  {
   case v[o][0]:
    if(sOpen(v[o][1])) return {cell:v[o][1]}
    if(sOpen(v[o][3])) return {cell:v[o][3]}
    break
   case v[o][1]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][2]:
    if(sOpen(v[o][1])) return {cell:v[o][1]}
    if(sOpen(v[o][5])) return {cell:v[o][5]}
    break
   case v[o][3]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][5]:
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][6]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][3]])) return {cell:v[o][3]}
    break
   case v[o][7]:
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][8]:
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][5]])) return {cell:v[o][5]}
    break
   default:
  }
 }
 else
 {
  switch(p)
  {
   case v[o][0]:
    if(mOpen(v[o][1])) return {cell:v[o][1]}
    if(mOpen(v[o][3])) return {cell:v[o][3]}
    break
   case v[o][1]:
    if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][2]:
    if(mOpen(v[o][1])) return {cell:v[o][1]}
    if(mOpen(v[o][5])) return {cell:v[o][5]}
    break
   case v[o][3]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][5]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][6]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][3]])) return {cell:v[o][3]}
    break
   case v[o][7]:
    if(view[v[o][0]].food&&mOpen([v[o][0]])) return {cell:v[o][0]}
    if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][8]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][5]])) return {cell:v[o][5]}
    break
   default:
  }
 }
 if(view[4].color==c1)
 {
  if(view[v[o][1]].color!=c1&&pootis(v[o][1])) return {cell:v[o][1],color:c1}
  if(view[v[o][0]].color!=c2&&pootis(v[o][0])) return {cell:v[o][0],color:c2}
  if(view[v[o][2]].color!=c3&&pootis(v[o][2])) return {cell:v[o][2],color:c3}
  if(view[v[o][3]].color!=c2) return {cell:v[o][3],color:c2}
  if(view[v[o][5]].color!=c3) return {cell:v[o][5],color:c3}
  if(view[v[o][6]].color!=c2) return {cell:v[o][6],color:c2}
  if(view[v[o][8]].color!=c3) return {cell:v[o][8],color:c3}
  if(view[v[o][7]].color!=c1) return {cell:v[o][7],color:c1}
 }
 return {cell:4}
}

function gather()
{
 if(view[4].ant.food>0)
 {
  if(view[4].color==c1&&(testSQ(c1,c2)||testSQ(c1,c3))) return gDoThing(c1,c3,c2)
  if(view[4].color==c2&&testSQ(c2,c1)) return gDoThing(c2,c1,c6)
  if(view[4].color==c3&&testSQ(c3,c1)) return gDoThing(c3,c6,c1)
  return wander(c5)
 }
 var n=fAlly(wq)
 if(n<0) return wander(c4)
 switch(n)
 {
  case 0:
   if(mOpen(8)) return {cell:8}
   if(mOpen(7)) return {cell:7}
   if(mOpen(5)) return {cell:5}
   break
  case 1:
   if(mOpen(6)) return {cell:6}
   if(mOpen(8)) return {cell:8}
   if(mOpen(7)) return {cell:7}
   break
  case 2:
   if(mOpen(6)) return {cell:6}
   if(mOpen(3)) return {cell:3}
   if(mOpen(7)) return {cell:7}
   break
  case 3:
   if(mOpen(8)) return {cell:8}
   if(mOpen(2)) return {cell:2}
   if(mOpen(5)) return {cell:5}
   break
  case 5:
   if(mOpen(0)) return {cell:0}
   if(mOpen(6)) return {cell:6}
   if(mOpen(3)) return {cell:3}
   break
  case 6:
   if(mOpen(2)) return {cell:2}
   if(mOpen(5)) return {cell:5}
   if(mOpen(1)) return {cell:1}
   break
  case 7:
   if(mOpen(2)) return {cell:2}
   if(mOpen(0)) return {cell:0}
   if(mOpen(1)) return {cell:1}
   break
  case 8:
   if(mOpen(0)) return {cell:0}
   if(mOpen(1)) return {cell:1}
   if(mOpen(3)) return {cell:3}
   break
  default:
   break
 }
 return {cell:4}
}

function testSQ(ac1,ac2)
{
 for(var i=0;i<4;i++)
 {
  if(view[r1[i]].color==ac1)
  {
   if(view[v[i][0]].color==ac2&&view[v[i][3]].color==ac2) return 1
   if(view[v[i][2]].color==ac2&&view[v[i][5]].color==ac2) return 1
  }
 }
 return 0
}

function gDoThing(ac1,ac2,ac3)
{
 var o=findOrient(ac1,ac2,ac3)
 if(view[v[o][1]].color!=ac1&&pootis(v[o][1])) return {cell:v[o][1],color:ac1}
 if(view[v[o][0]].color!=ac2&&pootis(v[o][0])) return {cell:v[o][0],color:ac2}
 if(view[v[o][2]].color!=ac3&&pootis(v[o][2])) return {cell:v[o][2],color:ac3}
 if(sOpen(v[o][1])) return {cell:v[o][1]}
 if(ac1==c2)
 {
  if(sOpen(v[o][0])) return {cell:v[o][0]}
  if(sOpen(v[o][3])) return {cell:v[o][3]}
  if(sOpen(v[o][6])) return {cell:v[o][6]}
 }
 else if(ac1==c3)
 {
  if(sOpen(v[o][2])) return {cell:v[o][2]}
  if(sOpen(v[o][5])) return {cell:v[o][5]}
  if(sOpen(v[o][8])) return {cell:v[o][8]}
 }
 else
 {
  if(sOpen(v[o][0])) return {cell:v[o][0]}
  if(sOpen(v[o][2])) return {cell:v[o][2]}
  if(sOpen(v[o][3])) return {cell:v[o][3]}
  if(sOpen(v[o][5])) return {cell:v[o][5]}
 }
 return {cell:4}
}

function pootis(p)
{
 var a=view[p].ant
 if(a!=null&&a.friend&&a.type==wg&&(view[p].color==c4||view[p].color==c5)) return 0
 return 1
}

function fAlly(t)
{
 var a=view[4].ant
 for(var i=0;i<9;i++)
 {
  if(i==4) i++
  a=view[i].ant
  if(a!=null&&a.friend&&a.type==t) return i
 }
 return -1
}

function fOpen()
{
 for(var i=0;i<9;i++)
 {
  if(i==4) i++
  if(sOpen(i)) return i
 }
 return -1
}

function sOpen(p)
{
 return (view[p].ant==null&&!view[p].food)
}

function mOpen(p)
{
 return (view[p].ant==null)
}

function wander(ac)
{
 if(view[4].ant.type==5||view[4].ant.food==0)
 {
  var vf = vFood()
  if(vf>=0) return {cell:vf}
  if(view[4].color!=ac) return {cell:4,color:ac}
  for(var i=0;i<4;i++)
  {
   if(view[x1[i]].color==ac&&view[x2[i]].color!=ac&&view[x2[i]].color!=c1&&mOpen(x2[i])) return {cell:x2[i]}
  }
  for(var i=0;i<4;i++)
  {
   if(mOpen(x1[i])&&view[x1[i]].color!=c1) return {cell:x1[i]}
  }
 }
 else
 {
  if(view[4].color!=ac) return {cell:4,color:ac}
  for(var i=0;i<4;i++)
  {
   if(view[x1[i]].color==ac&&view[x2[i]].color!=ac&&sOpen(x2[i])) return {cell:x2[i]}
  }
  for(var i=0;i<4;i++)
  {
   if(sOpen(x1[i])) return {cell:x1[i]}
  }
 }
 return {cell:4}
}

function findOrient(ac1,ac2,ac3)
{
 var w=[0,0,0,0]
 w[0]=DI(view[0].color,view[1].color,view[2].color,0,ac1,ac2,ac3)
 w[1]=DI(view[8].color,view[7].color,view[6].color,1,ac1,ac2,ac3)
 w[2]=DI(view[6].color,view[3].color,view[0].color,2,ac1,ac2,ac3)
 w[3]=DI(view[2].color,view[5].color,view[8].color,3,ac1,ac2,ac3)
 var t=[0,0,0,0]
 for(var i=0;i<4;i++)
 {
  switch(w[i])
  {
   case 4: t[0]++;break
   case 5: t[1]++;break
   case 6: t[2]++;break
   case 7: t[3]++;break
   case 8: t[0]+=2;break
   case 9: t[1]+=2;break
   case 10: t[2]+=2;break
   case 11: t[3]+=2;break
   case 12: t[0]+=3;break
   case 13: t[1]+=3;break
   case 14: t[2]+=3;break
   case 15: t[3]+=3;break
   default: break
  }
 }
 var m=Math.max(...t)
 for(var i=0;i<4;i++)
 {
  if(t[i]==m) return i
 }
 return 0
}

function DI(v1,v2,v3,d,ac1,ac2,ac3)
{
 var t=[0,0,0,0]
 switch(v1)
 {
  case ac2: t[0]++;t[3]++;break
  case ac3: t[1]++;t[2]++;break
  default: break
 }
 switch(v2)
 {
  case ac1: t[0]++;t[1]++;break
  case ac2: t[3]++;break
  case ac3: t[2]++;break
  default: break
 }
 switch(v3)
 {
  case ac2: t[1]++;t[3]++;break
  case ac3: t[0]++;t[2]++;break
  default: break
 }
 var m=Math.max(...t)
 if(m==0) return 0
 var n=0
 for(var i=0;i<4;i++)
 {
  if(t[i]==m){n=i;break}
 }
 if((d==2&&n==2)||(d==3&&n==3)) n=1
 else if((d==2&&n==3)||(d==3&&n==2)) n=0
 else n^=d
 return m*4+n
}

function vFood()
{
 for(var i=0;i<9;i++)
 {
  if(view[i].food) return i
 }
 return -1
}

function nColor(c)
{
 var t=0
 for(var i=0;i<9;i++)
 {
  if(view[i].color==c) t++
 }
 return t
}

요약하면, 여왕은 직선으로 움직이며 그녀의 뒤에 패턴을 만듭니다. 지원 노동자는 그녀의 바로 뒤에서 움직이고 그녀를 계속 유지하기 위해 만들어졌습니다. 또한 혼자 늑대 나 독신 여왕을 찾는 사냥꾼들이 있는데, 그들은 레일로 가져올 물건을 얻을 때까지 계속 갈 것이고, 그러면 그들을 여왕으로 데려 갈 것입니다.

자, 여기 버전 2가 있습니다. 이제 수집가들은 실제로 무언가를합니다.

버전 2.1 동일한 게임에서 블랙홀이 함께 나타날 때마다 블랙홀이 전체 트레일을 먹지 않도록 노란색 / 청록색 표시가 바뀌 었습니다.

버전 3. 보디 가드는 전면에서 추가적인 보호 기능을 제공하고 (레일에서 음식을 잡을 수 있도록) 추가되었으며, 수집가는 이제 트레일 지우개를 멀리하기 위해 검은 색 가장자리를 그려 블랙홀로부터 보호합니다. 또한 여왕은 조기 배치를 막기 위해 수집기 모드에서 청록색 타일을 피합니다.

좋아, 3.1 버전을위한 시간. Wildfire의 분노를 유발 하지 않고 트레일 지우개를 유지하기 위해 색상이 다시 변경되었습니다 . 수집가들은 또한 레일을 유지하고 더 잘 식별하기 위해 편집되었습니다 (새 레일을 만들거나 새 레일을 만들지 않음). 거기에 언급 할 수없는 다른 사소한 것들도 있습니다.

버전 3.2 : 보디 가드 관련 문제를 해결했습니다. 음식이 이미 있으면 더 이상 음식을 잡으려고 시도하지 않으며, 붙어 붙는 경향이 적으며, 여왕을 찾지 못하면 난간을 그릴 것입니다.


새로운 출품작 / 편집이있는 한 리더 보드가 어떻게 보이는지 확인하기 위해 새로운 토너먼트를 진행할 것입니다. 마감일이 없습니다. 현재 토너먼트는 독특한 1, 2, 3 위에 수렴되기까지 며칠이 남았을 것입니다. 그런 다음이 새로운 플레이어를 포함하여 새로운 토너먼트를 시작할 것입니다. 어떤 위치에 도달했는지 보여주기까지 일주일이 걸리는 것이 두렵습니다. 그러나 언제 도달하는지 알려 드리겠습니다.
trichoplax

@QuoteBeta 나는 당신의 편집증을 이해합니다 ... 나는이 도전을 보았으므로 도전의 기세가 멈추기 전에 엔트리를 만드는 과정에 있습니다.
Moogie

그럼 이것이 곧 끝날지 여부는 확실하지 않았습니다. 업데이트 속도가 약간 느려졌습니다.
QuoteBeta

대부분의 사람들은 아마도 끝났지 만 우리는 리더 보드를 기다리고 있습니다. 그리고 그들은 시간이 걸립니다.
Draco18s

개미가 내 흔적 정리 코드를 원할 것 같습니다 (블랙홀, 내부에서 개미가 길을 잃은 방법 참조). i.stack.imgur.com/DTmA6.png
Draco18s

6

부 영양 여왕

채색 된 지역을 피하려고 시도하는 동안 무작위로 걷는 여왕 전용 방법. 최고의 경쟁자는 아니지만 중간 정도의 성공과 변조 방지. 파라미터 조정이 진행 중입니다.

var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells
var move;
var scores = [];   // An array of how desirable each potential move is
var score, neighbor, claustrophobia, newColor;
var crowdedNeighbors = null;   // How many diagonal neighbors are colored CROWDED?
var runningFrom = null;    // When in running phase, which direction did we come from?
var runningTo = null;      // When in running phase, which direction should we head?

// Assign color magic numbers to variables
var EMPTY = 1;
var VISITED = 4;
var CROWDED = 7;
var RUNNING = 8;

function neighbors(cell) {
    switch (cell) {
        case 0: return [1, 3];
        case 1: return [0, 2];
        case 2: return [1, 5];
        case 3: return [0, 6];
        case 4: return orthogonals;
        case 5: return [2, 8];
        case 6: return [3, 7];
        case 7: return [6, 8];
        case 8: return [7, 5];
        default: return null;
    }
}

function isHungry(ant) {
    if (ant.type === 5 || ant.food === 0) {
        return true;
    } else {
        return false;
    }
}

// Color own cell based on the number of neighbors that are colored
claustrophobia = 0;
for (i=0; i<9; i++) {
    if (view[i].color !== EMPTY || i === 4) {
        claustrophobia++;
    }
    if (i % 2 === 0 && i !== 4) {
        if (view[i].color === CROWDED) {
            crowdedNeighbors++;
        } else if (view[i].color === RUNNING) {
            crowdedNeighbors++;
            runningFrom = i;
        }
    }
}

if (claustrophobia > 4) {
    if (crowdedNeighbors > 1 || runningFrom !== null) {
        // We're entering or currently in a straight-line running state
        // in which we keep going until we find sufficient whitespace
        newColor = RUNNING;
    } else {
        newColor = CROWDED;
    }
} else {
    newColor = VISITED;
}
if (view[4].color !== newColor) {
    return {cell:4, color:newColor}
}

// If we've already colored the current cell properly, and we're in running mode,
// then move diametrically away from the runningFrom cell
switch (runningFrom) {
    case 0:
        runningTo = 8;
        break;
    case 2:
        runningTo = 6;
        break;
    case 6:
        runningTo = 2;
        break;
    case 8:
        runningTo = 0;
        break;
    default:
        break;
}

// Calculate a score for each potential move
// Lower numbers are better; null means illegal move
// Unexplored areas are better; food is the best (as long as ant can eat); don't move onto other ants
for (i=0; i<9; i++) {
    // Base score of tile is 2 times color of tile
    score = 2 * (view[i].color);
    // Add colors of neighboring tiles
    for (neighbor of neighbors(i)) {
        score += view[neighbor].color;
    }
    // Give very good score to runningTo tile, unless it's also RUNNING color
    if (i === runningTo && view[i].color !== RUNNING) {
        score -= 4;   // Magic number, possibly to be tweaked
    }
    if (i!==4 && view[i].ant) {
        // Tile contains another ant; give very bad score
        score = null;
    } else if (view[i].food) {
        // If a tile contains food, it's either highly desirable if the ant can eat, or illegal if it can't
        if (isHungry(view[4].ant)) {
            // Ant can eat; give food tile very good score
            score = -1;
        } else {
            // Ant cannot eat; give food tile very bad score
            score = null;
        }
    }
    scores.push(score);
}

// Select best move based on the scores array
move = 4;   // By default, stay put (this probably won't be the best move)
for (i=0; i<9; i++) {
    if (scores[i] !== null && scores[i] < scores[move]) {
        move = i;
    }
}

return {cell:move};

여왕은 이동하면서 청록색의 흔적을 내려 놓습니다. 그녀는 빈 셀과 빈 이웃이있는 셀로 이동하는 것을 우선시합니다. 현재 수학이 나오는 방식은 대부분 대각선으로 움직이며 바둑판 패턴입니다. 현재 셀에 네 개 이상의 색상이 지정된 이웃이 있으면 시안 대신 파란색으로 표시됩니다. 파란색 셀은 우선 순위가 높은 것을 피합니다. 마지막으로 여왕이 두 개의 파란색 셀에 인접하면 다시 열린 영역에 도달 할 때까지 검은 색 대각선으로 시작합니다.

여기에 이미지 설명을 입력하십시오


부정 조작 방지; 흔적 지우개가 흔적을 지울 수 있으며, 개미가 원을 그리며 돌아 다닐 수 있습니다.
pppery

1
어, 사각형으로?
pppery

1
@ppperry 나는 " 중간 ... 조작 방지 "라고 말했다 . ;) Trail-Eraser가 할 수있는 유일한 일은 이미 다루어 진 땅을 덮을 가능성을 높이는 것입니다. 그러나 그것은 탐험되지 않은 영토로 쉽게 이동할 수 있습니다.
DLosc

6

호페 마우어

우선이 멋진 도전을 한 Trichoplax에게 감사의 말씀을 전합니다.이 사이트에 가입하고 자바 스크립트로 프로그래밍을 시작했습니다. 이 질문의 대화방에 아직도 숨어있는 다른 사람들, 심지어 질문을 받은지 정확히 3 개월이 지난 후에도 감사합니다.

내 봇은 처음에는 진지한 경쟁자가 아니지만, 임의의 보행 접근을 피하는 단일 퀸 / 자기, 약간 점프하는 Claustrophobic Queen 과 같습니다 .

페인트 패턴으로 Hoppemaur 봇 디테일

암호

//Hoppemaur
//å hoppe: to jump
//maur: ant

var WHITE = 1;
var OWN = 2;
var FOOD = 6;
var ESCAPE = 3;
var paint = 0;
var score = {0:2,1:-3,2:2,3:-3,4:-1,5:-3,6:2,7:-3,8:2}; 
// The ant should only walk diagonal (except when feeding)
var highest = 0;
var scoreindex;
var diagonals = [0, 2, 6, 8];
var diagonalsandself = [0, 2, 4, 6, 8]
var inversdiagonals = [8, 6, 2, 0];
var orthogonals = [1, 3, 5, 7];
var inverseorthogonals = [7, 5, 3, 1];
var rotate1orthogonals = [3, 1, 7, 5];
var rotate2orthogonals = [5, 7, 1, 3];

//checks if one of the diagonals or the own tile are painted
function checkforemptypattern() {
  for (var i=0; i<diagonalsandself.length; i++) {
    if (view[diagonalsandself[i]].color == OWN){
     return false;}
  }
  return true;
}

//counts the diagonals painted in the requestest colour
function checktrapped(pattern) {
  var diags=0;
  for (var i=0; i<diagonals.length; i++) {
    if (view[diagonals[i]].color == pattern){
     diags=diags+1;
    }
  }
return diags;
}

//Biggest threat to this ant is food on orthogonals,
//it messes up the pattern if not dealt with it
if (view[4].color !== FOOD){
    for (var i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].food) {
            return {cell:4, color:FOOD};
            }
        }
    }

if (view[4].color == FOOD){
    for (var i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].food) {
        if (!view[orthogonals[i]].ant){
            return {cell:orthogonals[i]};
            }
        }
        }
    }

//If food shows up on diagonals while out of pattern,
//before grabbing food, the pattern must be painted
for (var i=0; i<diagonals.length; i++){
    if (view[diagonals[i]].food){
        if (checkforemptypattern()){
            return {cell:4, color: OWN}
            }
        }
    }


//Otherwise, food can easily be grabbed if not ant in way
for (var i=0; i<9; i++) {
    if (view[i].food) {
        if(!view[i].ant){
        return {cell:i}
        }
    }
}


//After food has been grabbed orthogonal, back to food pile
if (view[4].color == WHITE){
    for (i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].color == FOOD && checktrapped(FOOD) == 0 && view[inverseorthogonals[i]].color !== FOOD && view[rotate1orthogonals[i]].color !== FOOD && view[rotate2orthogonals[i]].color !== FOOD){
                 if (!view[orthogonals[i]].ant){
                     return {cell:orthogonals[i]};
                     }
                 }
        }
    }

//First part of scoring
// Scoring to determine next move
// Scoring everything higher than own pattern and escape
for (var i=0; i<9; i++) {
  if (view[i].color !== OWN) {
      score[i] = score[i]+3;
  }
  if (view[i].color !== ESCAPE){
      score[i] = score[i]+5;
  }
}

// Scoring while in painted area (f.e. wildfire)

var l = 0;
for (var i=2; i<9; i++) {
                          var k = 0;
    for (var j=0; j<9; j++) {
                             if (view[j].color == i) {
            k=k+1;
            if (k > 6){
            paint=i;
            }
        if (view[j].color !==WHITE) {
          l=l+1;

        }
    }
}
}

if (paint !== OWN && l >7) {
    for (var i=0; i<diagonals.length; i++){
        if (view[diagonals[i]].color == OWN) {
            score[inversdiagonals[i]]=score[inversdiagonals[i]]+7;
            }
        if (view[diagonals[i]].color == WHITE) {
          score[diagonals[i]]=score[diagonals[i]]+7
        }
        }
    }


if (paint == OWN && l >7) {
    for (var i=0; i<diagonals.length; i++){
        if (view[diagonals[i]].color == ESCAPE) {
            score[inversdiagonals[i]]=score[inversdiagonals[i]]+7;
            }
        if (view[diagonals[i]].color == WHITE) {
          score[diagonals[i]]=score[diagonals[i]]+7
        }
        }
    }

// the following might lead to some traps?
// score diagonals adjactant to white higher
  if (view[1].color === WHITE) {
    score[0] = score[0]+1;
    score[2] = score[2]+1;
   }
  if (view[3].color === WHITE) {
    score[0] = score[0]+1;
    score[6] = score[6]+1;
   }
  if (view[5].color === WHITE) {
    score[2] = score[2]+1;
    score[8] = score[8]+1;
   }
  if (view[7].color === WHITE) {
    score[6] = score[6]+1;
    score[8] = score[8]+1;
   }


//Don't move next to others, they steal your food!
  if (view[0].ant || view[1].ant || view[2].ant){
      score[6] = score [6]+10;
      score[8] = score [8]+10;
  }

  if (view[0].ant || view[3].ant || view[6].ant){
      score[2] = score [2]+10;
      score[8] = score [8]+10;
  }

  if (view[6].ant || view[7].ant || view[8].ant){
      score[0] = score [0]+10;
      score[2] = score [2]+10;

  }
   if (view[2].ant || view[5].ant || view[8].ant){
      score[0] = score [0]+10;
      score[6] = score [6]+10;

  }
//don't step on others!
for (var i=0; i<9; i++) {
  if (i!==4 && view[i].ant) {
        score[i] = -5;
 }
}

//end of scoring, calculate best
for (var i=0; i<9; i++) {
  if (score[i] > highest) {
    highest = score[i];
    scoreindex = i;
    }
  }

//Basic enemy avoidance
for (var i=0; i<9; i++) {
  if (i!==4 && view[i].ant) {
        return {cell:scoreindex}
        }
  }

//basic movement

//when surrounded by other paint
if (paint == ESCAPE && l>7){
    if(view[4].color == OWN){
      return{cell:scoreindex}
    }
}

if (paint !== OWN && paint !== 0 && l>7){
  if(view[4].color !== OWN){
    return{cell:4, color:OWN}
  }
}


if (paint == OWN && l>7){
  if(view[4].color !== ESCAPE){
    return{cell:4, color:ESCAPE}
  }
}

//a) when off pattern
if (view[4].color !== OWN) {
    if (view[4].color == ESCAPE){
         if (checktrapped(ESCAPE)==4){
            return{cell:scoreindex}
            }
        }
        if (view[4].color == ESCAPE){
         if (checktrapped(ESCAPE)==3){
            return{cell:scoreindex}
            }
        }
    if (checkforemptypattern()) {
    return{cell:4, color:OWN};
    }

    //Am I trapped? Different possible traps follow here
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==4){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==3 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==2 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==2 && checktrapped(ESCAPE)==2){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==1 && checktrapped(ESCAPE)==2){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==1 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){ //when the orthogonals are painted, some other guy was here before and movement traps are likely
         if (view[1].color == OWN || view[7].color == OWN || view[3].color == OWN || view[5].color == OWN){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){ //when the orthogonals are painted, some other guy was here before and movement traps are likely
         if (view[1].color == ESCAPE || view[7].color == ESCAPE || view[3].color == ESCAPE || view[5].color == ESCAPE){
            return{cell:4, color:ESCAPE}
            }
    }
}

//b) when on pattern check surroundings for escape route
if (checktrapped(ESCAPE)==3){
    return{cell:4, color:ESCAPE}
}
if (checktrapped(ESCAPE)==4){
    return{cell:4, color:ESCAPE}
}

//otherwise just move on
return{cell:scoreindex}

설명

이 봇의 주요 아이디어는 이미 방문한 영역을 식별 할 수있는 채 페인팅 시간을 단축하는 것이 었습니다. 이를 달성하기 위해 여왕은 일반적으로 매 두 번째 움직임 후에 만 ​​페인트합니다. 그러나 그렇게하면 이동 방향 정보가 손실되어 방향이없는 점프 패턴이 발생합니다. 진정한 무작위 보행을 피하기 위해 여왕은 이미 페인트 칠한 타일보다 페인트 칠하지 않은 타일을 더 높게 평가하고 역 추적의 경우 분홍색 탈출 색상을 사용하여 이전에 자신에게 있음을 알립니다. 전술 한 바와 같은 스코어링 메커니즘은 일반적인 움직임의 중추를 제공한다.

가장 큰 위험 중 하나는 대각선 움직임 패턴을 벗어난 음식물입니다. 그녀가 그에 걸려 넘어지면 녹색을 사용하여 패턴을 벗어나지 않기 위해 음식을 잡은 후에 돌아올 원점을 표시합니다. 봇의 마지막 부분은 핑크 이스케이프 색상이 사용될 다양한 상황을 처리합니다.

또한 기본 적 회피 및 이미 페인트 칠한 영역에서의 대각선 이동도 포함됩니다 (그러나 실제로 테스트되지는 않았습니다).

마지막으로, 봇은 혼자있을 때 몇 가지 아름다운 추상 패턴을 그립니다.

게임 종료시 Hoppemaur 봇 개요 패턴


3
사이트에 오신 것을 환영합니다! KoTH 과제는 일반적이지 않지만 가장 쉬운 침입 방법입니다. 나는 공식적으로 끝난 경우에도 시도해 볼 수있는 컨트롤러가있는 3 ~ 4 개의 구형 컨트롤러가 여전히 있다고 생각합니다. CodeBots 4 (코드를 서로 주입하는 봇) 및 Prisoners Dillema 3 (페트리 디쉬). 또한 원정대 전투와 전세계 유행병. PD가 Python에 있다는 것을 알고 CB가 Java에 있다고 생각합니다. 다른 것을 기억하지 마십시오.
Draco18s

감사합니다, @ Draco18s! 나는 식민지 개미 봇 :-) 구축 관리하기 전에 나는하지만, 그 이전의 문제를 확인 할 수
펠레 Lundkvist

6

대형

이 제출물은 github 저장소 에서 호스팅됩니다 .

var marcher_count;var gatherer_count;var excess_gatherers;var tcell;var lh_cell;var rh_cell;var ant_off;var alt_cell;var cell_off;function debug(message)
{}
const MARCHER_A=1;const MARCHER_B=2;const GATHERER=3;const QUEEN=5;const S_END=[6,5,7,4,0,2,1,3];const S_FRONT=[7,5,6,0,4,1,3,2];const S_SIDE=[7,3,5,1,6,2,0,4];const S_GATHERER=[7,6,5,4,0,3,2,1];const SCAN_MOVES=[0,1,2,3,5,6,7,8];const CORNERS=[0,2,6,8];const EDGES=[1,3,5,7];const CCW=[[0,3,6,7,8,5,2,1],[1,0,3,6,7,8,5,2],[2,1,0,3,6,7,8,5],[3,6,7,8,5,2,1,0],[4,4,4,4,4,4,4,4],[5,2,1,0,3,6,7,8],[6,7,8,5,2,1,0,3],[7,8,5,2,1,0,3,6],[8,5,2,1,0,3,6,7]];const NEARS=[[6,5,3,5,4,2,3,2,1],[5,6,5,4,5,4,2,3,2],[3,5,6,2,4,5,1,2,3],[5,4,2,6,5,3,5,4,2],[4,5,4,5,6,5,4,5,4],[2,4,5,3,5,6,2,4,5],[3,2,1,5,4,2,6,5,3],[2,3,2,4,5,4,5,6,5],[1,2,3,2,4,5,3,5,6]];const SAN_ORD=[[1,3,6,2,5,7,8],[0,2,5,3,6,8,7],[5,1,0,8,7,3,6],[6,0,1,7,8,2,5],[],[2,8,7,1,0,6,3],[3,7,8,0,1,5,2],[8,6,3,5,2,0,1],[7,5,2,6,3,1,0]];const D_MARCH=1;const D_FOOD=2;const D_STALLED=3;const D_GATHERER=4;const U_REALIGN=5;const U_SENTINEL=6;const U_READY=7;const U_PANIC=8;const PUPS=[[0,1,2,3,4,5,6,7,8],[1,1,0,0,0,1,1,0,1],[2,0,2,0,4,2,2,0,2],[3,0,0,3,4,3,3,0,3],[4,0,4,4,4,4,0,0,4],[5,1,2,3,4,5,5,0,5],[6,1,2,3,0,5,5,0,6],[7,0,0,0,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const PDOWNS=[[0,1,2,3,4,5,6,7,8],[1,1,0,3,4,5,5,0,1],[2,0,2,3,4,5,5,0,2],[3,3,3,3,3,3,3,3,3],[4,4,4,3,4,0,0,0,4],[5,5,5,3,0,5,5,0,5],[6,5,5,3,0,5,5,0,6],[7,0,0,3,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const PSIDES=[[0,1,2,3,4,5,6,7,8],[1,1,0,3,4,1,1,0,1],[2,0,2,0,4,5,5,0,2],[3,3,0,3,3,3,3,3,3],[4,4,4,3,4,0,0,0,4],[5,1,5,3,0,5,5,0,5],[6,1,5,3,0,5,5,0,6],[7,0,0,3,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const INIT_SEED=3734978372;const FINAL_SEED=2338395782;const SRECOLOR_PROB=0.7;const SONSTRIDE_PROB=0.5;const QFSPAWNP_MAX=0.05;const QFSPAWNP_MIN=0.00;const QFSPAWNP_DECAY=0.005;const QBSPAWNP_MAX=0.65;const QBSPAWNP_MIN=0.55;const QBSPAWNP_DECAY=0.01;const QFORMP_MAX=0.5;const QFORMP_MIN=0.3;const QFORMP_DECAY=0.01;const DISCOLORT=35;const ERASET=20;const SOBSTRUCT_FUZZ=6;const SSTRIDE_FUZZ=6;const OBSTRUCT_QWT=3;const SPREFWT=2;var state=null;function rand_init()
{state=INIT_SEED;for(var cell=0;cell<9;cell++)
{var v=view[cell];state^=v.color;state^=v.food<<3;if(v.ant!==null)
{state^=v.ant.friend<<4;state^=v.ant.type<<5;state^=v.ant.food<<8;}
ant_rand();}
state^=FINAL_SEED;if(state===0)state=1;}
function ant_rand()
{if(state===null)rand_init();state^=state<<13;state^=state>>>17;state^=state<<5;return state>>>0;}
function rand_choice(prob)
{return ant_rand()/4294967296<prob;}
function rand_sub(array,num)
{var return_array=array.slice();for(var i=0;i<num;i++)
{var rand_index=i+ant_rand()%(array.length-i);var x_val=return_array[rand_index];return_array[rand_index]=return_array[i];return_array[i]=x_val;}
return return_array.slice(0,num);}
function rand_perm(array)
{var return_array=array.slice();for(var i=0;i<array.length-1;i++)
{var rand_index=i+ant_rand()%(array.length-i)
var x_val=return_array[rand_index];return_array[rand_index]=return_array[i];return_array[i]=x_val;}
return return_array;}
function index_sort(arr)
{var index_array=[];for(var i=0;i<arr.length;i++)index_array.push(i);index_array.sort((a,b)=>(arr[a]===arr[b])?(a-b):(arr[a]-arr[b]));return index_array;}
function this_ant()
{return view[4].ant;}
function c_at(cell)
{return view[cell].color;}
function is_ally(cell)
{return view[cell].ant!==null&&view[cell].ant.friend===true;}
function is_enemy(cell)
{return view[cell].ant!==null&&view[cell].ant.friend===false;}
function is_harvestable(cell)
{return is_enemy(cell)&&view[cell].ant.type===QUEEN&&view[cell].ant.food>0;}
function lchk(c)
{if(is_ally(CCW[c][6])&&view[CCW[c][6]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type===GATHERER&&is_ally(CCW[c][1]))return D_GATHERER;if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type===GATHERER)
if(is_ally(CCW[c][3])&&c_at(4)===D_MARCH)return D_STALLED;if(view[CCW[c][6]].food===1&&is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][7]].food===1&&is_ally(CCW[c][1])&&c_at(CCW[c][1])===D_FOOD)return D_FOOD;if(view[CCW[c][5]].food===1&&is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;return null;}
function lchk2(c)
{if(is_ally(CCW[c][6])&&view[CCW[c][6]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type===GATHERER&&is_ally(CCW[c][1]))return D_GATHERER;if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type===GATHERER)
if(is_ally(CCW[c][3])&&c_at(4)===D_MARCH)return D_STALLED;if(is_ally(CCW[c][2])&&view[CCW[c][2]].ant.type===GATHERER)
if(is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&c_at(CCW[c][5])===D_GATHERER)return D_GATHERER;if(is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type===GATHERER)
if(is_ally(CCW[c][7])&&c_at(4)===D_MARCH)return D_STALLED;if(view[CCW[c][6]].food===1&&is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][7]].food===1&&is_ally(CCW[c][1])&&c_at(CCW[c][1])===D_FOOD)return D_FOOD;if(view[CCW[c][5]].food===1&&is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;if(view[CCW[c][2]].food===1&&is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][3]].food===1&&is_ally(CCW[c][5])&&c_at(CCW[c][5])===D_FOOD)return{cell:4,color:D_FOOD};if(view[CCW[c][1]].food===1&&is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;return null;}
function sigc(output,order,c)
{if(c_at(4)===output)
for(cell_off of order)
{var tcell=CCW[c][cell_off];if(!is_ally(tcell)&&c_at(tcell)!==D_MARCH)
{if(view[tcell].food!==0&&view[tcell].color===D_FOOD)
{for(alt_cell of SCAN_MOVES)
{var n_wt=NEARS[tcell][alt_cell];if(n_wt>3&&n_wt<6&&is_ally(alt_cell))
if(view[alt_cell].ant.type===QUEEN||view[alt_cell].ant.type===GATHERER)
continue;}}
return{cell:tcell,color:D_MARCH};}}
return{cell:4,color:output};}
function is_gatherer_marcher(cell)
{if(!is_ally(cell)||view[cell].ant.food>0||view[cell].ant.type!==GATHERER)return false;if(this_ant().type===QUEEN)return true;lh_cell=CCW[cell][1];rh_cell=CCW[cell][7];if(is_ally(lh_cell)&&view[lh_cell].ant.type===QUEEN)return!is_ally(rh_cell)
else if(is_ally(rh_cell)&&view[rh_cell].ant.type===QUEEN)return!is_ally(lh_cell)
else return false;}
function is_like(cell)
{if(c_at(cell)===U_PANIC)return false;if(is_ally(CCW[cell][1])&&c_at(CCW[cell][1])===U_PANIC)return false;if(is_ally(CCW[cell][7])&&c_at(CCW[cell][7])===U_PANIC)return false;if(CORNERS.includes(cell)&&is_ally(cell))
{switch(view[cell].ant.type)
{case MARCHER_A:return view[cell].ant.food===0&&this_ant().type!==MARCHER_B;case MARCHER_B:return view[cell].ant.food===0&&this_ant().type!==MARCHER_A;case GATHERER:return is_gatherer_marcher(cell)&&this_ant().type!==GATHERER;case QUEEN:return true;default:return false;}}
return false;}
function is_other(cell)
{if(c_at(cell)===U_PANIC)return false;if(EDGES.includes(cell)&&is_ally(cell))
{switch(view[cell].ant.type)
{case MARCHER_A:return view[cell].ant.food===0&&this_ant().type!==MARCHER_A;case MARCHER_B:return view[cell].ant.food===0&&this_ant().type!==MARCHER_B;case GATHERER:return this_ant().type===QUEEN
case QUEEN:return true;default:return false;}}
return false;}
function view_corner()
{var scores=[0,0,0,0];for(var i=0;i<4;i++)
for(var j=0;j<8;j++)
{scores[i]*=2;var tcell=CCW[CORNERS[i]][j];if(is_ally(tcell)&&(is_like(tcell)||is_other(tcell)))scores[i]++;}
if(scores[0]>scores[1]&&scores[0]>scores[2]&&scores[0]>scores[3])return CORNERS[0];else if(scores[1]>scores[2]&&scores[1]>scores[3])return CORNERS[1];else if(scores[2]>scores[3])return CORNERS[2];else return CORNERS[3];}
const ONE_EDGE=10;const ONE_CORNER=11;const EE_BENT=20;const EE_STRAIGHT=21;const EC_LEFT=22;const EC_RIGHT=23;const EC_SKEWED=24;const EC_SPAWN=25;const CC_EDGED=26;const CC_LINE=27;const THREE_MARCH=30;const THREE_STAND=31;const THREE_RECOVER=32;const THREE_UNSTAND=33;const THREE_BLOCK=34;const THREE_HANG=35;const THREE_UNHANG=36;const THREE_SIDE=37;const FOUR_Z=40;const FOUR_STAIRS=41;const FOUR_BENT=42;function neighbor_type(top_left)
{var corners=[];for(tcell of CORNERS)
if(is_ally(tcell)&&is_like(tcell))corners.push(tcell);var edges=[];for(tcell of EDGES)
if(is_ally(tcell)&&is_other(tcell))edges.push(tcell);if(corners.length===1&&edges.length===0)return ONE_CORNER;if(corners.length===0&&edges.length===1)return ONE_EDGE;if(corners.length===0&&edges.length===2)return(edges[1]===CCW[edges[0]][4])?EE_STRAIGHT:EE_BENT;if(corners.length===2&&edges.length===0)return(corners[1]===CCW[corners[0]][4])?CC_LINE:CC_EDGED;else if(corners.length===1&&edges.length===1)
{if(edges[0]===CCW[top_left][1])return EC_LEFT;if(edges[0]===CCW[top_left][3])return EC_SPAWN;if(edges[0]===CCW[top_left][5])return EC_SKEWED;if(edges[0]===CCW[top_left][7])return EC_RIGHT;return null;}
else if(corners.length===1&&edges.length===2)
{if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3]))return THREE_MARCH;if(edges.includes(CCW[top_left][3])&&edges.includes(CCW[top_left][7]))return THREE_STAND;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][5]))return THREE_RECOVER;if(edges.includes(CCW[top_left][5])&&edges.includes(CCW[top_left][7]))return THREE_UNSTAND;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][7]))return THREE_BLOCK;return null;}
else if(corners.length===2&&edges.length===1)
{if(corners.includes(CCW[top_left][4])&&edges.includes(CCW[top_left][3]))return THREE_HANG;if(corners.includes(CCW[top_left][4])&&edges.includes(CCW[top_left][1]))return THREE_UNHANG;if(corners.includes(CCW[top_left][2])&&edges.includes(CCW[top_left][1]))return THREE_SIDE;}
else if(corners.length===2&&edges.length===2)
{if(edges.includes(CCW[top_left][3])&&edges.includes(CCW[top_left][7])&&corners.includes(CCW[top_left][4]))
return FOUR_Z;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3])&&corners.includes(CCW[top_left][4]))
return FOUR_STAIRS;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3])&&corners.includes(CCW[top_left][2]))
return FOUR_BENT;return null;}
return null;}
function sok(cand)
{if(cand===4)return true;if(view[cand].food!==0&&this_ant().food!==0)return false;if(view[cand].ant!==null)return false;return true;}
function spref(cand)
{var okscore=0;if(cand===4)okscore-=9;if(this_ant().type===GATHERER)
{for(tcell of SCAN_MOVES)
if(NEARS[cand][tcell]>1)
if(is_ally(tcell)&&view[tcell].ant.type===QUEEN)okscore-=1;}
else
{if(this_ant().food===0&&view[cand].food!==0)
{for(tcell of SCAN_MOVES)
if(is_ally(tcell)&&view[tcell].ant.food===0)
{if([MARCHER_A,MARCHER_B].includes(view[tcell].ant.type))
{var has_common_enemy=false;for(var i=0;i<9;i++)
if(is_enemy(i)&&NEARS[tcell][i]>=4)has_common_enemy=true;if(!has_common_enemy)
{var wt=(view[tcell].ant.type===this_ant().type)?1:-1;if(NEARS[4][tcell]===5)okscore+=wt;if(NEARS[4][tcell]===4)okscore-=wt;if(NEARS[cand][tcell]===5)okscore-=wt;if(NEARS[cand][tcell]===4)okscore+=wt;}}}
if(okscore>0)okscore=0;}}
return okscore*SPREFWT;}
function ssep()
{var has_ally=false;var cands=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)cands[i]+=spref(i);for(tcell of SCAN_MOVES)
{if(is_ally(tcell))
{has_ally=true;var wt=(is_like(tcell)||is_other(tcell))?3:1;for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i]*wt;}}
if(!has_ally)return null;var prox_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(sok(i_cell))return{cell:i_cell};}
return null;}
function sstep(col)
{if(c_at(4)===1)return{cell:4,color:col};var cands=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
if(c_at(tcell)===col)
for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i];for(var i=0;i<9;i++)cands[i]+=spref(i);var prox_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(sok(i_cell))return{cell:i_cell};}
return{cell:4,color:col};}
function smove()
{for(tcell of rand_perm(SCAN_MOVES))
if(sok(tcell))return{cell:tcell};return{cell:4};}
function sdec_alone()
{var try_sep=ssep();if(try_sep!==null)return try_sep;var c=U_PANIC;for(tcell of rand_sub(SCAN_MOVES,7))
if(c_at(tcell)>1&&c_at(tcell)!==c)
{c=c_at(tcell);break;}
return sstep(c);}
function sdec_erase()
{var try_sep=ssep();if(try_sep!==null)return try_sep;for(tcell of rand_perm(SCAN_MOVES))
if(c_at(tcell)!==1)return{cell:tcell,color:1};if(c_at(4)!==1)return{cell:4,color:1};return sdec_alone();}
function sdec_discolor()
{if(c_at(1)!==c_at(6)&&c_at(6)!==1)return{cell:1,color:c_at(6)};if(c_at(2)!==c_at(3))return{cell:3,color:c_at(2)};var proximities=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ+spref(i);for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];var prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return smove();}
function sdec_stride()
{if(rand_choice(SONSTRIDE_PROB))
{var stride_scores=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{for(var i=0;i<9;i++)
if(c_at(tcell)!==c_at(i)&&c_at(i)!==1)stride_scores[i]+=NEARS[tcell][i];}
for(var i=0;i<9;i++)
stride_scores[i]+=ant_rand()%SSTRIDE_FUZZ+spref(i);var prox_order=index_sort(stride_scores);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};}
return smove();}
function sdec_obstruct_textured()
{var proximities=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(is_enemy(tcell))
{var wt=(view[tcell].ant.type===QUEEN)?OBSTRUCT_QWT:1;for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i]*wt;}}
for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ;var prox_order;if(rand_choice(SRECOLOR_PROB))
{prox_order=index_sort(proximities);for(var i=8;i>0;i--)
{var i_cell=prox_order[i];for(var j=0;j<i;j++)
{var j_cell=prox_order[j];if(c_at(i_cell)!==c_at(j_cell))return{cell:i_cell,color:c_at(j_cell)};}}}
for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];for(var i=0;i<9;i++)proximities[i]+=spref(i);prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return{cell:4,color:1};}
function sdec_obstruct_flat()
{var proximities=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(is_enemy(tcell))
{var wt=(view[tcell].ant.type===QUEEN)?OBSTRUCT_QWT:1;for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i]*wt;}}
for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ;var prox_order;if(rand_choice(SRECOLOR_PROB))
{prox_order=index_sort(proximities);for(var i=8;i>0;i--)
{var i_cell=prox_order[i];if(c_at(i_cell)!==D_MARCH)return{cell:i_cell,color:D_MARCH};}}
for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];for(var i=0;i<9;i++)proximities[i]+=spref(i);prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return{cell:4,color:1};}
function saboteur()
{var colored_neighbors=0;for(tcell of SCAN_MOVES)
if(c_at(tcell)>1)colored_neighbors++;if(colored_neighbors<=2)return sdec_alone();else
{var num_enemies=0;for(tcell of SCAN_MOVES)
if(is_enemy(tcell))num_enemies++;var diversity=0;var counts=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)
{diversity+=5-counts[c_at(i)];counts[c_at(i)]++;}
if(num_enemies>0)
{if(diversity>=ERASET)return sdec_obstruct_textured();else return sdec_obstruct_flat();}
else
{if(diversity>=DISCOLORT)return sdec_discolor();else if(diversity>=ERASET)return sdec_stride();else return sdec_erase();}}}
function gwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0&&this_ant().food!==0)return sigc(U_PANIC,S_SIDE,0);if(view[cand.cell].ant!==null)return sigc(U_PANIC,S_SIDE,0);return cand;}
function egwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0&&this_ant().food!==0)return gwatch(sdec_erase());if(view[cand.cell].ant!==null)return gwatch(sdec_erase());return cand;}
function gdec_ee_bent(c)
{return{cell:CCW[c][4]};}
function gdec_ec_left(c)
{if(c_at(c)===D_FOOD&&c_at(CCW[c][1])===D_FOOD)return{cell:CCW[c][7]};if(c_at(c)===D_STALLED&&c_at(CCW[c][1])===D_STALLED)return sigc(U_READY,S_GATHERER,c);if(c_at(c)===D_MARCH&&c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_GATHERER,c);return sigc(c_at(4),S_GATHERER,c);}
function gdec_ec_right(c)
{if([D_MARCH,D_FOOD].includes(c_at(c))&&[D_MARCH,D_FOOD].includes(c_at(CCW[c][7])))
return{cell:CCW[c][6]};if(is_ally(c)&&view[c].ant.type===QUEEN)
return{cell:CCW[c][1]};if(c_at(c)===D_STALLED&&c_at(CCW[c][7])===D_STALLED)
return sigc(U_READY,S_GATHERER,c);return sigc(c_at(4),S_GATHERER,c);}
function gdec_cc_edged(c)
{if(view[CCW[c][2]].ant.type!==QUEEN)return saboteur();return{cell:CCW[c][1]};}
function gdec_three_block(c)
{if(c_at(CCW[c][7])==D_FOOD)return{cell:CCW[c][6]};return{cell:CCW[c][2]};}
function gdec_three_unstand(c)
{if(view[CCW[c][5]].ant.type!==QUEEN)return saboteur();return{cell:CCW[c][4]};}
function gdec_four_bent(c)
{return{cell:CCW[c][4]};}
function early_gatherer()
{var qcell=null;var food_count=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell)&&view[tcell].ant.type===QUEEN)qcell=tcell;else if(is_enemy(tcell))return saboteur();}
if(qcell===null)return saboteur();if(c_at(qcell)===D_FOOD)return{cell:CCW[qcell][7]};if(this_ant().food===0)
{for(tcell of rand_perm(CORNERS))
if(view[tcell].food>0&&NEARS[tcell][qcell]===5)
{if(c_at(tcell)===D_FOOD)return{cell:tcell};else return{cell:tcell,color:D_FOOD};}
for(tcell of rand_perm(EDGES))
if(view[tcell].food>0)
{if(c_at(tcell)!==D_FOOD&&NEARS[tcell][qcell]===4)
return{cell:tcell,color:D_FOOD};}}
return{cell:CCW[qcell][1]};}
function gatherer_retrieve()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch({cell:CCW[c][2]});case THREE_BLOCK:{if(c_at(CCW[c][7])===D_FOOD)return gwatch({cell:CCW[c][6]});return gwatch({cell:CCW[c][2]});}
case FOUR_BENT:return gwatch(sigc(c_at(4),S_FRONT,c));default:return early_gatherer();}}
function gatherer_return()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch({cell:CCW[c][2]});case THREE_BLOCK:return gwatch({cell:CCW[c][2]});case FOUR_BENT:return gwatch({cell:CCW[c][4]});default:return early_gatherer();}}
function gatherer_formation()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch(gdec_ec_left(c));case EC_RIGHT:return gwatch(gdec_ec_right(c));case CC_EDGED:return gwatch(gdec_cc_edged(c));case EE_BENT:return gwatch(gdec_ee_bent(c));case THREE_BLOCK:return gwatch(gdec_three_block(c));case THREE_UNSTAND:return gwatch(gdec_three_unstand(c));case FOUR_BENT:return gwatch(gdec_four_bent(c));default:return egwatch(early_gatherer());}}
function gatherer_decision()
{var marcher_count=0;var gatherer_count=0;var queen_pos=null;for(tcell of SCAN_MOVES)
if(is_ally(tcell))
{if(view[tcell].ant.type===MARCHER_A||view[tcell].ant.type===MARCHER_B)marcher_count++;if(view[tcell].ant.type===GATHERER)gatherer_count++;if(view[tcell].ant.type===QUEEN)queen_pos=tcell;}
if(gatherer_count>0)return saboteur();if(this_ant().food>0&&marcher_count>0)return gwatch(gatherer_return());else if(queen_pos!==null&&marcher_count>0)return gwatch(gatherer_formation());else if(marcher_count>0)return gwatch(gatherer_retrieve());else if(queen_pos!==null)return egwatch(early_gatherer());else return saboteur();}
function mdec_one_corner(c)
{if(view[c].ant.type===QUEEN)
return sigc(c_at(4),S_SIDE,c);else return saboteur();}
function mdec_one_edge(c)
{if([U_REALIGN,D_MARCH].includes(c_at(CCW[c][1])))
{if(view[CCW[c][2]].food===1)return{cell:c};if(is_ally(CCW[c][2])&&view[CCW[c][2]].ant.type===GATHERER)return{cell:c};}
return saboteur();}
function mdec_ee_bent(c)
{if(view[CCW[c][1]].ant.type===GATHERER&&view[CCW[c][3]].ant.type===QUEEN)return saboteur();if(view[CCW[c][1]].ant.type===QUEEN&&view[CCW[c][3]].ant.type===GATHERER)return saboteur();var u_sig=c_at(CCW[c][1]);var d_sig=c_at(CCW[c][3]);if(is_ally(c)&&view[c].ant.type===GATHERER)return sigc(c_at(4),S_SIDE,CCW[c][4]);var provisional=lchk(c);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,c);return sigc(provisional,S_END,c);}
if(u_sig===D_STALLED)
{if([D_STALLED,U_READY,D_GATHERER].includes(d_sig)&&[D_STALLED,U_READY].includes(c_at(4)))
return sigc(D_STALLED,S_SIDE,c);if(d_sig===U_REALIGN&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_SIDE,c);}
if(view[CCW[c][1]].ant.type===QUEEN)
{var provisional=lchk(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_END,CCW[c][4]);if(u_sig===D_GATHERER&&d_sig===U_REALIGN&&c_at(4)===D_GATHERER)
return sigc(D_GATHERER,S_END,CCW[c][4]);}
if(u_sig===U_SENTINEL)
{if(d_sig===U_REALIGN&&[D_MARCH,U_SENTINEL].includes(c_at(4)))return sigc(U_SENTINEL,S_SIDE,c);if(d_sig===D_STALLED&&[U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(U_SENTINEL,S_SIDE,c);if(d_sig===D_MARCH&&[U_SENTINEL,D_MARCH].includes(c_at(4)))return sigc(D_MARCH,S_SIDE,c);}
if(u_sig===D_GATHERER&&d_sig===D_STALLED&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_SIDE,c);return{cell:CCW[c][2]};}
function mdec_ee_straight(c)
{return sigc(U_REALIGN,S_SIDE,c);}
function mdec_ec_left(c)
{if(view[CCW[c][1]].ant.type===GATHERER&&view[c].ant.type===QUEEN)return saboteur();if(view[CCW[c][1]].ant.type===QUEEN&&view[c].ant.type===GATHERER)return saboteur();if(is_other(CCW[c][1])&&view[c].ant.type===QUEEN)return{cell:CCW[c][3]};var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][1])];if(is_ally(CCW[c][4])&&view[CCW[c][4]].ant.type===GATHERER&&d_sig===D_STALLED&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_END,c);var provisional=lchk(CCW[c][4]);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,CCW[c][4]);return sigc(provisional,S_END,CCW[c][4]);}
if(d_sig===U_REALIGN)
{if(c_at(4)===D_MARCH)return sigc(U_SENTINEL,S_END,CCW[c][4]);if(c_at(4)===U_SENTINEL)
{if(c_at(c)===D_MARCH)return{cell:CCW[c][2]};return sigc(U_SENTINEL,S_END,CCW[c][4]);}}
if(d_sig===D_STALLED)
{if([D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);if(c_at(4)===U_SENTINEL)return sigc(U_SENTINEL,S_END,CCW[c][4]);}
if(d_sig===D_GATHERER)
{if(c_at(4)===D_FOOD)return sigc(D_GATHERER,S_END,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)
{if(c_at(CCW[c][2])!==D_MARCH)return{cell:CCW[c][2],color:D_MARCH};return sigc(D_MARCH,S_END,CCW[c][4]);}
if(c_at(4)===U_SENTINEL)return sigc(D_MARCH,S_END,CCW[c][4]);}
return{cell:CCW[c][2]};}
function mdec_ec_right(c)
{if(view[c].ant.type===GATHERER&&view[CCW[c][7]].ant.type===QUEEN)
if(is_ally(CCW[c][4])&&view[CCW[c][4]].ant.type!==this_ant().type)return{cell:CCW[c][5]};var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][7])];var provisional=lchk(CCW[c][4]);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,CCW[c][4]);return sigc(provisional,S_END,CCW[c][4]);}
if(d_sig===D_MARCH)
{if(c_at(4)===D_MARCH)return sigc(D_MARCH,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);}
if(d_sig===D_FOOD)
{if([U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===D_GATHERER)
{if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);if([U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(D_MARCH,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);}
if(d_sig===U_REALIGN)
{if(c_at(4)===U_SENTINEL)return{cell:CCW[c][6]};if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
return sigc(d_sig,S_END,CCW[c][4]);}
function mdec_ec_spawn(c)
{if(view[c].ant.type===QUEEN&&c_at(c)===D_MARCH&&c_at(CCW[c][3])===D_STALLED)
if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);return saboteur();}
function mdec_three_march(c)
{var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][1])];var u_sig=c_at(CCW[c][3]);var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(u_sig===U_SENTINEL)
{if(d_sig===D_GATHERER&&[D_GATHERER,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_STALLED&&[D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===U_REALIGN)
{if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)
if(c_at(c)===U_SENTINEL)
{if(c_at(CCW[c][7])===D_MARCH)return sigc(U_REALIGN,S_FRONT,c);return{cell:CCW[c][2]};}
if(d_sig===D_FOOD&&[D_MARCH,D_FOOD].includes(c_at(4)))return sigc(D_FOOD,S_FRONT,c);if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(D_MARCH,S_FRONT,c);if(d_sig===D_STALLED&&[D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&[D_GATHERER,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_MARCH&&c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===D_MARCH)
{if(d_sig===D_FOOD&&c_at(4)===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(d_sig===U_REALIGN&&c_at(4)===D_MARCH)
if(c_at(c)===U_SENTINEL)return sigc(U_REALIGN,S_FRONT,c);if(d_sig===U_READY&&c_at(4)===U_READY)return sigc(D_MARCH,S_FRONT,c);}
if(u_sig===D_STALLED)
{if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);if(d_sig===D_STALLED&&[D_STALLED,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_MARCH&&c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,c);if(d_sig===U_REALIGN&&[D_STALLED,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===D_GATHERER)
{if(d_sig===D_STALLED&&c_at(4)===D_GATHERER)
if(view[CCW[c][3]].ant.type===QUEEN)return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(d_sig===D_FOOD&&c_at(4)===D_GATHERER)return sigc(D_FOOD,S_FRONT,c);}
if(u_sig===D_FOOD)
{if(d_sig===D_FOOD&&c_at(4)===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);}
return{cell:CCW[c][2]};}
function mdec_three_stand(c)
{var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_SIDE,c);var u_sig=c_at(CCW[c][3]);var d_sig=PSIDES[c_at(c)][c_at(CCW[c][7])];if(u_sig===U_REALIGN)
{if([D_MARCH,D_STALLED].includes(d_sig)&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_MARCH&&d_sig===U_REALIGN&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(u_sig===D_STALLED&&[D_STALLED,U_REALIGN].includes(d_sig)&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_SIDE,CCW[c][4]);return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
function mdec_three_unstand(c)
{if(view[CCW[c][5]].ant.type===QUEEN)
{var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);var d_sig=PUPS[c_at(c)][c_at(CCW[c][7])];return sigc(d_sig,S_FRONT,c);}
else
{var provisional=lchk(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_FRONT,CCW[c][4]);var u_sig=c_at(CCW[c][5]);var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_MARCH)
{if(d_sig===U_READY&&c_at(4)===U_READY)return sigc(D_MARCH,S_FRONT,CCW[c][4]);if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_MARCH,S_FRONT,CCW[c][4]);}
if(u_sig===D_FOOD)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===D_GATHERER)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===D_STALLED)
{if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_FOOD)
{if(c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===D_GATHERER)
return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_FOOD)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_REALIGN)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_SENTINEL)
{if(d_sig===D_FOOD)
{if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);}
if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(d_sig===D_MARCH&&c_at(4)===U_SENTINEL)return sigc(D_MARCH,S_FRONT,CCW[c][4]);if(d_sig===D_STALLED&&c_at(4)===U_SENTINEL)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_READY)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_MARCH,S_FRONT,CCW[c][4]);}
return sigc(c_at(4),S_FRONT,CCW[c][4]);}}
function mdec_three_recover(c)
{return sigc(U_SENTINEL,S_FRONT,c);}
function mdec_three_hang(c)
{return sigc(c_at(4),S_SIDE,CCW[c][4]);}
function mdec_three_unhang(c)
{return sigc(c_at(4),S_SIDE,c);}
function mdec_four_z(c)
{var provisional=lchk2(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_SIDE,CCW[c][4]);var u_sig=PSIDES[c_at(c)][c_at(CCW[c][7])];var d_sig=PSIDES[c_at(CCW[c][4])][c_at(CCW[c][3])];if(u_sig===D_FOOD)
{if([D_FOOD,D_STALLED,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_GATHERER&&[U_REALIGN,D_GATHERER].includes(c_at(4)))
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_STALLED)
{if(d_sig===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_GATHERER)
{if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,CCW[c][4]);if(d_sig===D_FOOD&&[U_REALIGN,D_GATHERER].includes(c_at(4)))
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===U_REALIGN)
{if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_STALLED)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,CCW[c][4]);if(d_sig===U_READY&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
if(u_sig===U_READY&&d_sig===U_REALIGN&&c_at(4)===U_REALIGN)
return sigc(D_MARCH,S_SIDE,CCW[c][4]);return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
function mdec_four_stairs(c)
{var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_SIDE,c);var u_sig=PSIDES[c_at(c)][c_at(CCW[c][1])];var d_sig=PSIDES[c_at(CCW[c][4])][c_at(CCW[c][3])];if(u_sig===D_MARCH)
{if(d_sig===D_FOOD)
{if(c_at(4)===D_MARCH)return sigc(D_FOOD,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===U_READY)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(u_sig===D_FOOD)
{if(d_sig===D_MARCH)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===D_MARCH)return sigc(D_FOOD,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER&&[U_REALIGN,D_GATHERER].includes(c_at(4)))return sigc(D_FOOD,S_SIDE,c);if([U_REALIGN,D_STALLED].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===D_STALLED)
{if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===D_MARCH)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if([D_STALLED,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(U_READY,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===U_REALIGN&&[U_REALIGN,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===D_GATHERER)
{if(d_sig===D_STALLED)
{if([D_STALLED,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_FOOD&&[D_GATHERER,U_REALIGN].includes(c_at(4)))return sigc(D_FOOD,S_SIDE,c);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===U_REALIGN)
{if(d_sig===U_REALIGN)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_MARCH&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if([D_FOOD,D_GATHERER,U_READY].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===U_READY)
{if(d_sig===D_MARCH)
{if(c_at(4)===U_READY)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
if([D_FOOD,D_GATHERER].includes(d_sig))
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
if(d_sig===D_STALLED&&c_at(4)===D_STALLED)return sigc(U_READY,S_SIDE,c);if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if(d_sig===U_READY&&c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
return sigc(c_at(4),S_SIDE,c);}
function mwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0)return sigc(D_FOOD,S_SIDE,0);if(is_harvestable(cand.cell))return sigc(D_FOOD,S_SIDE,0);if(view[cand.cell].ant!==null)return sigc(U_PANIC,S_SIDE,0);return cand;}
function marcher_decision()
{if(c_at(4)===U_PANIC||this_ant().food>0)return saboteur();var gatherer_count=0;var enemy_count=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell)&&view[tcell].ant.type===GATHERER)gatherer_count++;else if(is_enemy(tcell)&&!is_harvestable(tcell))enemy_count++;}
if(gatherer_count>1||enemy_count>0)return saboteur();var colored_neighbors=0;for(tcell of SCAN_MOVES)
if(c_at(tcell)>1)colored_neighbors++;if(colored_neighbors>5)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case ONE_CORNER:return mwatch(mdec_one_corner(c));case ONE_EDGE:return mwatch(mdec_one_edge(c));case EE_BENT:return mwatch(mdec_ee_bent(c));case EE_STRAIGHT:return mwatch(mdec_ee_straight(c));case EC_LEFT:return mwatch(mdec_ec_left(c));case EC_RIGHT:return mwatch(mdec_ec_right(c));case EC_SPAWN:return mwatch(mdec_ec_spawn(c));case THREE_MARCH:return mwatch(mdec_three_march(c));case THREE_STAND:return mwatch(mdec_three_stand(c));case THREE_RECOVER:return mwatch(mdec_three_recover(c));case THREE_UNSTAND:return mwatch(mdec_three_unstand(c));case THREE_HANG:return mwatch(mdec_three_hang(c));case THREE_UNHANG:return mwatch(mdec_three_unhang(c));case FOUR_Z:return mwatch(mdec_four_z(c));case FOUR_STAIRS:return mwatch(mdec_four_stairs(c));default:return saboteur();}}
function opening_queen()
{for(tcell of rand_perm(SCAN_MOVES))
if(view[tcell].food===1)return{cell:tcell};var has_ally=false;var proxs=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(view[tcell].ant!==null)
{has_ally=true;for(var i=0;i<9;i++)proxs[i]-=NEARS[tcell][i];}}
if(has_ally)
{var prox_order=index_sort(proxs);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(view[i_cell].ant===null&&view[i_cell].food===0)return{cell:i_cell};}}
if(this_ant().food>0)
{var num_ants=0;for(tcell of SCAN_MOVES)
if(view[tcell].ant!==null)num_ants++;if(num_ants===0)
{var is_clear=true;var num_black_corners=0;var black_corner=null;for(var tcell=0;tcell<9;tcell++)
{if(CORNERS.includes(tcell))
{if(c_at(tcell)===8)
{num_black_corners++;black_corner=tcell;}
else if(c_at(tcell)!==1)is_clear=false;}
else if(c_at(tcell)!==1)is_clear=false;}
if(num_black_corners===1&&is_clear)return{cell:CCW[black_corner][7],type:GATHERER};}}
if(c_at(4)!==8)return{cell:4,color:8};var cands=[0,0,0,0,9,0,0,0,0];for(tcell of SCAN_MOVES)
if(c_at(tcell)===8)
for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i];var cand_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=cand_order[i];if(view[i_cell].ant===null&&view[i_cell].food===0)return{cell:i_cell};}
return{cell:4,color:8};}
function early_queen()
{var gcell=null;var ally_count=0;for(tcell of rand_perm(SCAN_MOVES))
{if(is_ally(tcell))
{ally_count++;if(view[tcell].ant.type===GATHERER&&EDGES.includes(tcell))gcell=tcell;}}
if(gcell===null)return opening_queen();for(tcell of rand_perm(CORNERS))
if(view[tcell].food>0&&NEARS[tcell][gcell]===5)
{if(c_at(tcell)===D_FOOD)return{cell:tcell};else return{cell:tcell,color:D_FOOD};}
for(tcell of rand_perm(EDGES))
if(view[tcell].food>0)
{if(c_at(tcell)!==D_FOOD&&NEARS[tcell][gcell]===4)
return{cell:tcell,color:D_FOOD};}
if(c_at(4)===D_FOOD)
{if(c_at(CCW[gcell][2])===D_FOOD&&view[CCW[gcell][2]].food===0)
return{cell:CCW[gcell][2],color:D_MARCH};return{cell:4,color:D_MARCH};}
if(c_at(CCW[gcell][6])===D_FOOD&&view[CCW[gcell][6]].food===0)
return{cell:CCW[gcell][6],color:D_MARCH};if(EDGES.includes(gcell)&&this_ant().food>2&&ally_count===1)
{var num_clear_cells=0;var num_down_food=0;var is_valid=true;for(var tcell=0;tcell<9;tcell++)
{if(c_at(tcell)===D_FOOD)
{num_down_food++;if(tcell!==4&&tcell!==gcell)is_valid=false;}
if(c_at(tcell)===D_MARCH)num_clear_cells++;}
if(is_valid&&num_down_food===1&&num_clear_cells===8)
{var food_factor=QFORMP_MAX-QFORMP_MIN
var food_coefficient=QFORMP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-3)+1)+QFORMP_MIN;if(rand_choice(actual_prob))return{cell:CCW[gcell][1],type:rand_choice(.5)?MARCHER_A:MARCHER_B};else return{cell:gcell,color:D_MARCH};}}
return{cell:CCW[gcell][7]};}
function qwatch(cand)
{if(cand.hasOwnProperty("type")&&this_ant().food===0)return sigc(U_PANIC,S_SIDE,0);if(cand.hasOwnProperty("type")&&view[cand.cell].food!==0)return sigc(U_PANIC,S_SIDE,0);if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(is_enemy(cand.cell))return sigc(U_PANIC,S_SIDE,0);if(is_ally(cand.cell))return sigc(c_at(4),S_SIDE,0);return cand;}
function eqwatch(cand)
{if(cand.hasOwnProperty("type")&&this_ant().food===0)return qwatch(opening_queen());if(cand.hasOwnProperty("type")&&view[cand.cell].food!==0)return qwatch(opening_queen());if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(is_enemy(cand.cell))return qwatch(opening_queen());if(is_ally(cand.cell))return qwatch(opening_queen());return cand;}
function qdec_ee_straight(c)
{return sigc(c_at(4),S_SIDE,c);}
function qdec_ee_bent(c)
{return{cell:CCW[c][2]};}
function qdec_ec_skewed(c)
{if(view[CCW[c][5]].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[c].ant.type===MARCHER_A)return{cell:CCW[c][7],type:MARCHER_B};if(this_ant().food>0&&view[c].ant.type===MARCHER_B)return{cell:CCW[c][7],type:MARCHER_A};return opening_queen();}
function qdec_ec_spawn(c)
{if(view[CCW[c][3]].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[c].ant.type===MARCHER_A)return{cell:CCW[c][1],type:MARCHER_B};if(this_ant().food>0&&view[c].ant.type===MARCHER_B)return{cell:CCW[c][1],type:MARCHER_A};return opening_queen();}
function qdec_cc_edged(c)
{if(view[c].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[CCW[c][2]].ant.type===MARCHER_A)return{cell:CCW[c][1],type:MARCHER_B};if(this_ant().food>0&&view[CCW[c][2]].ant.type===MARCHER_B)return{cell:CCW[c][1],type:MARCHER_A};return opening_queen();}
function qdec_three_march(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_STALLED)
{if(c_at(CCW[c][3])===D_MARCH&&[D_MARCH,D_GATHERER].includes(c_at(4)))
return sigc(D_STALLED,S_FRONT,c);if(c_at(CCW[c][3])===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);}
if(u_sig===D_MARCH&&c_at(CCW[c][3])===U_READY&&c_at(4)===U_READY)
return sigc(D_MARCH,S_FRONT,c);if(u_sig===U_READY&&c_at(CCW[c][3])===U_REALIGN&&c_at(4)===U_READY)
if(c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_stand(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_STALLED)
{if(c_at(CCW[c][3])===D_MARCH&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,c);if(c_at(CCW[c][3])===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);}
if(u_sig===D_MARCH&&c_at(CCW[c][3])===U_READY&&c_at(4)===U_READY)
return sigc(D_MARCH,S_FRONT,c);if(u_sig===U_READY&&c_at(CCW[c][3])===U_REALIGN&&c_at(4)===U_READY)
if(c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_recover(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(this_ant().food>0&&[D_STALLED,U_READY].includes(u_sig))
{var food_factor=QFSPAWNP_MAX-QFSPAWNP_MIN
var food_coefficient=QFSPAWNP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-1)+1)+QFSPAWNP_MIN;if(rand_choice(actual_prob))return{cell:CCW[c][3]};}
var provisional=lchk(c)
if(provisional!==null)return sigc(provisional,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_unstand(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(this_ant().food>0&&u_sig===D_STALLED&&c_at(CCW[c][5])===D_MARCH&&c_at(4)===D_STALLED)
{var food_factor=QBSPAWNP_MAX-QBSPAWNP_MIN
var food_coefficient=QBSPAWNP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-1)+1)+QBSPAWNP_MIN;if(rand_choice(actual_prob))return{cell:CCW[c][3]};}
if(u_sig===D_STALLED&&c_at(CCW[c][5])===U_READY&&c_at(4)===D_STALLED)
return sigc(U_READY,S_FRONT,c);return sigc(u_sig,S_FRONT,c);}
function qdec_three_block(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];return sigc(u_sig,S_FRONT,c);}
function qdec_three_side(c)
{var u_sig=PUPS[c_at(CCW[c][1])][c_at(CCW[c][2])];return sigc(u_sig,S_FRONT,CCW[c][2]);}
function queen_wait()
{var c=view_corner();switch(neighbor_type(c))
{case ONE_EDGE:{if(this_ant().food>1)return{cell:CCW[c][3],type:GATHERER};}
break;case EC_LEFT:{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(u_sig===U_REALIGN&&[U_REALIGN,U_SENTINEL].includes(c_at(c)))
if([U_REALIGN,U_SENTINEL].includes(c_at(CCW[c][1])))
return eqwatch(early_queen());var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(this_ant().food>1)
{if(c_at(CCW[c][3])!==D_MARCH)return{cell:CCW[c][3],color:D_MARCH};return{cell:CCW[c][3],type:GATHERER};}}
break;case EC_RIGHT:{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(u_sig===U_REALIGN&&[U_REALIGN,U_SENTINEL].includes(c_at(c)))
if([U_REALIGN,U_SENTINEL].includes(c_at(CCW[c][7])))
return eqwatch(early_queen());var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(this_ant().food>1)
{if(c_at(CCW[c][5])!==D_MARCH)return{cell:CCW[c][5],color:D_MARCH};return{cell:CCW[c][5],type:GATHERER};}}
break;}
if(c_at(4)!==U_PANIC)return sigc(U_PANIC,S_SIDE,c);else return opening_queen();}
function queen_march()
{var c=view_corner();switch(neighbor_type(c))
{case EE_STRAIGHT:return qwatch(qdec_ee_straight(c));case EE_BENT:return qwatch(qdec_ee_bent(c));case EC_SKEWED:return qwatch(qdec_ec_skewed(c));case EC_SPAWN:return qwatch(qdec_ec_spawn(c));case CC_EDGED:return qwatch(qdec_cc_edged(c));case THREE_MARCH:return qwatch(qdec_three_march(c));case THREE_STAND:return qwatch(qdec_three_stand(c));case THREE_RECOVER:return qwatch(qdec_three_recover(c));case THREE_UNSTAND:return qwatch(qdec_three_unstand(c));case THREE_BLOCK:return qwatch(qdec_three_block(c));case THREE_SIDE:return qwatch(qdec_three_side(c));default:return eqwatch(early_queen());}}
function queen_decision()
{marcher_count=0;gatherer_count=0;excess_gatherers=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell))
{if(view[tcell].ant.type===MARCHER_A||view[tcell].ant.type===MARCHER_B)marcher_count++;if(view[tcell].ant.type===GATHERER)
{if(EDGES.includes(tcell)||is_gatherer_marcher(tcell))gatherer_count++;else excess_gatherers++;}}
else if(is_enemy(tcell))return opening_queen();}
if(marcher_count>0&&gatherer_count===1&&excess_gatherers===0)return qwatch(queen_march());else if(marcher_count>0&&gatherer_count===0&&excess_gatherers===0)return qwatch(queen_wait());else if(gatherer_count===1&&excess_gatherers===0)return eqwatch(early_queen());else return opening_queen();}
function main_decide()
{switch(this_ant().type)
{case QUEEN:return queen_decision();case GATHERER:return gatherer_decision();case MARCHER_A:case MARCHER_B:return marcher_decision();default:return sanitize(saboteur());}}
return main_decide();

개요

이 제출은 해당 지역을 쓸 수있는 개미 줄을 만드는 것을 목표로합니다. 색상은 여왕이 선로 표시자가 아니라 선을 조정하는 데 도움이되는 신호로 사용됩니다.

이 제출물은 여왕 외에도 세 가지 유형의 근로자를 사용합니다.

  • 유형 1 : 대형 행군, 단계
  • 유형 2 : 대형 행군, B 단계
  • 유형 3 : 수집가
  • 유형 4 : 향후 사용을 위해 예약 됨

개미는 다음과 같이 전각 대각선으로 작성됩니다.

    A
    BA
     BA
      BA
       BA
        BA
         BA
          QG

처음 네 개미 개미는 같은 확률로 수집가와 행진 자 A 또는 B이며 각각 개미입니다. 그 후, 개미는 음식을 찾은 후 A와 B를 번갈아 가며 확률로 생성됩니다. 대형에서 여왕 수집가는 마지막으로 생성 된 대형 행군에 따라 두 단계의 행진을 번갈아 가며 만듭니다.

초기 단계

여왕이 산란 할 때, 그녀는 경로를 다시 추적하지 않기 위해 늪지대 표준 반 광속 직선 걷기를 수행합니다. 이것이 그녀에게 하나의 음식을 얻었을 때, 그녀는 수집가를 생성합니다. 3 개의 음식을 모은 후, 모든 추가 음식에 대해, 여왕은 하드 코딩 된 형성 생성 루틴에서 3 명의 노동자를 산란 할 가능성이 적당하며, 그 노선이 이륙합니다.

일반적인 행동

개미는 정지 단계와 이동 단계 사이에서 번갈아 가면서 단계 A와 단계 B 개미와 함께 잠금 단계로 행진합니다. 개미가 상태를 저장할 수 없기 때문에 단계는 인접한 동맹국의 패턴과 일치하여 인식됩니다. 개미는 항상 두 개 이상의 다른 개미에 인접 해 있도록 움직입니다.

개미가 장애물 뒤에 대각선으로 있으면 턴을 돌려 적절한 신호를 내립니다. 이 신호는 여왕을 향해 즉시 내려 가며 (창조 순서에있는 모든 노동자에게 감사함), 위쪽으로는 빛의 속도 만 관리 할 수 ​​있습니다. 인접한 상류 행군은 신호를 인식하고 신호를 전파하여 다른 신호를 라인 위로 발사합니다.

실수로 또는 공황 신호에 의해 회선에서 분리 된 작업자는 방해 행위자가되어 둥지를 짓밟으며 적군 근로자를 방해하려고 시도합니다. 그들은 재 설립이 실용적이지 않기 때문에 그들이 그것을 가로 지르면 형성을 적극적으로 피할 것입니다.

음식 모음

음식이 나오면 줄이 멈 춥니 다. 그러나 신호는 광속 업스트림 만 관리 할 수 ​​있기 때문에 신호가 위쪽으로 전파되는 데 시간이 걸리므로 업스트림이 직선으로 구부러집니다. 끝의 개미는 고리에 구부려서 완전히 똑바로 펴지는 것을 방지하지만 정지됩니다.

음식을 만난 노동자는 모든 하류 개미가 중계하고주의를 기울이는 일반적인 명확한 신호 대신 음식 신호를 쏴 버립니다. 다음 차례, 동일한 신호가 업스트림으로 인식되고 재 배열 신호로 변환되어 업스트림으로 이동하여 작업자가 신호를 수신 할 때 업스트림을 중단시킵니다. 마지막에 마지막 작업자는 다른 작업자와의 근접성을 유지하기 위해 끝에 굽힘을 유지합니다.

다운 스트림 신호는 한 번의 턴으로 퀸에게 전달되며, 수집기는 라인을 걷는 신호로 인식합니다. 음식 신호의 가장자리를 따라 수집가는 음식을 찾을 때까지 앞으로 걸어 간 다음 반대 방향으로 가서 여왕에게 돌려줍니다. 보류중인 음식이 더 있으면 음식 신호가 지속됩니다. 그렇지 않으면 정지 된 신호가 이제 라인을 쏘아 여왕에게 준비된 신호를 쏘라고 신호를 보내고,이 신호는 구부러진 지점에 행진 신호를 쏘아냅니다.

라인이 행진으로 되돌아 가면, 실속 된 작업자는 라인이 따라 올 때 행진을 재개합니다. 신호가 들어 오면 개미에게 프로세스가 발생하므로, 재정렬 신호가 라인의 끝에 도달하기 전에 라인이 재개되거나 라인의 업스트림 부분이 다운 스트림에서 정지되는 것이 전적으로 실용적이며 발생합니다. 다운 스트림에서 재정렬 신호를 수신합니다.

선에서

이 라인은 전단력을 견뎌내도록 설계되었으며, 퀸 및 수집 자와 함께 3 인 이상의 연속 된 작업자 라인은 생성 순서대로 완전한 기능을 갖춘 행군 형성입니다. 이 라인은 상당히 신뢰할 만하지 만 적의 작업자에 의한 방해에 취약합니다. 이런 일이 발생하면, 적의 일꾼 앞에 가장 직접적인 개미가 공황 신호를 보냅니다. 다음 차례, 그것은 선을 깎아 내리고 독자적으로 출발합니다. 그 다음에 모든 상류 노동자들이 그 뒤에 누군가를 갖지 못했을 때 불일치를 발견하고 마찬가지로 행동합니다. 다운 스트림 행거는이 이벤트로 인해 방해받지 않고 계속 행진합니다.

선로에서 벗어나면, 노동자는 방해꾼이된다. 그들은 원래의 영역과 다소 유사하지만 중첩 기능에 중요한 패턴을 포함하지 않는 혼란을 만들기 위해 주변 영역으로 컬러 영역을 다시 칠하려고 시도합니다. 그들은 적군 노동자들을 적극적으로 고수하고 그들을 방해하거나 오도하려고 시도하며, 동맹국이 전선을 방해하는 것을 막기 위해 동맹국을 적극적으로 피할 것입니다. 색상으로 둘러싸여 있지 않으면 직선 반 광속 보행을 수행하여 새로운 색상 영역을 혼합합니다.

무질서한 노동자는 무자비하게 포메이션을 형성 할 수 있지만, 올바른 끝을 정박하는 여왕이 없다는 것은 곧 헤어질 것임을 의미해야한다. 그렇지 않은 경우 버그를 제기하십시오.

엑스트라

여왕 약탈은 진행중인 작업입니다. 노동자들은 적의 여왕이 아닌 적의 여왕을 음식으로 인식 할 것이지만, 나중에 이것이 어떻게 상호 작용하는지는 테스트되지 않았으며 조정되지 않았습니다.

기존의 컬러 신호가 회선을 방해하지 않도록하기 위해 작업자는 컬러 신호를 보내면 주변 영역을 흰색으로 다시 칠하지만 이미 보내려는 컬러 신호에 서 있습니다. 이 주변 청소는 너무 강력하여 행진 형성이 문제없이 최대 속도로 유색 둥지를 뚫을 수 있습니다.

퀸 스폰은 확률에 의해 제어됩니다. 게임이 진행되고 여왕이 더 많은 음식을 먹을 때, 그녀는 조정 가능한 점근 제한 확률로 줄을 바꾸고 새로운 줄을 만들고 기존 줄에 노동자를 추가하기를 간절히 원합니다.

할 것

  • 논리적 부스러기 청소
  • 여왕 약탈 테스트 및 개선
  • 적군 노동자가 걸어 다닐 수 있는지 확인하십시오
  • 신호 상태 감소 조사
  • 최종 작업자가 본격적으로 깎아내는 것이 도움이되는지 확인하십시오

릴리즈 노트

1.0 : 최초 버전 제출, 최초 출시

1.0.1 : 더 많은 컨트롤러와 호환되는 논리적 축소 수행

1.1 : 오류 사례와 관련된 여러 가지 요소를 압축하고 개선 된 논리

1.1.1 : 실격 문제를 해결하기위한 핫픽스

1.2 : 추가 교착 상태 제거, 파괴자는 이제 정밀 검사

1.3 : 여왕의 산란율 감소, 파괴자들에게 튠업 제공

1.3.1 : 여왕 산란 속도가 더욱 감소하고 실격 버그가 수정되었습니다.

1.4 : 파라미터 튜닝


5

강압 개미

/*Ants will try to move diagonally in the following fashion:
 * 2
 * 51
 *
 *Type 1 and queen are the two core ants
 */


switch (view[4].ant.type) {

  case 1: //Guiding ant
    //Look for queen, try to move diagonally
    if (view[7].ant && view[7].ant.friend && view[7].ant.type === 5 && !view[8].ant) return {cell: 8};
    else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 5 && !view[2].ant) return {cell: 2};
    else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 5 && !view[6].ant) return {cell: 6};
    else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 5 && !view[0].ant) return {cell: 0};
    else return {cell: 4};
  case 2: //Other wing
    //Look for queen, try to move diagonally. If there is food, rotate the other way to start rotating procedure
    if (view[7].ant && view[7].ant.friend && view[7].ant.type === 5 && !view[6].ant) {
      if (view[6].food) {
        if (!view[8].ant) return {cell: 8};
        else return {cell: 4};
      } else return {cell: 6};
    } else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 5 && !view[8].ant) {
      if (view[8].food) {
        if (!view[2].ant) return {cell: 2};
        else return {cell: 4};
      } else return {cell: 8};
    } else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 5 && !view[0].ant) {
      if (view[0].food) {
        if (!view[6].ant) return {cell: 6};
        else return {cell: 4};
      } else return {cell: 0};
    } else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 5 && !view[2].ant) {
      if (view[2].food) {
        if (!view[0].ant) return {cell: 0};
        else return {cell: 4};
      } else return {cell: 2};
    } else return {cell: 4};
  case 5: //Queen ant

    //If forever alone
    if (!view[1].ant && !view[3].ant && !view[5].ant && !view[7].ant) {
      if (view[4].color === 2) { //If on colored square, try to move
        if (view[0].color === 2 && !view[8].ant) return {cell: 8};
        else if (view[2].color === 2 && !view[6].ant) return {cell: 6};
        else if (view[6].color === 2 && !view[2].ant) return {cell: 2};
        else if (view[8].color === 2 && !view[0].ant) return {cell: 0};
        //Can't find color, or path is blocked? try diagonals regardless of color
        else if (!view[0].ant) return {cell: 0};
        else if (!view[2].ant) return {cell: 2};
        else if (!view[6].ant) return {cell: 6};
        else if (!view[8].ant) return {cell: 8};
        //Everything else failed? Stay put.
        else return {cell: 4};
      } else { //If not on colored square, look for food, or set current color to 2.
        if (view[4].ant.food >= 1) { //Try to make Guiding ant
          if (!view[1].ant && !view[1].food) return {cell: 1, type: 1};
          else if (!view[3].ant && !view[3].food) return {cell: 3, type: 1};
          else if (!view[5].ant && !view[5].food) return {cell: 5, type: 1};
          else if (!view[7].ant && !view[7].food) return {cell: 7, type: 1};
        }
        for (var i = 0; i < 9; i++) { //Look for food
          if (view[i].food) return {cell: i};
        }
        return {cell: 4, color:2};
      }
    } else { //Queen has partner
      //Make other wing
      if (view[4].ant.food >= 1) {
        if (view[1].ant && view[1].ant.friend && view[1].ant.type === 1 && !view[3].ant && !view[3].food && !view[5].ant) return {cell: 3, type: 2};
        else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 1 && !view[7].ant && !view[7].food && !view[1].ant) return {cell: 7, type: 2};
        else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 1 && !view[1].ant && !view[1].food && !view[7].ant) return {cell: 1, type: 2};
        else if (view[7].ant && view[7].ant.friend && view[7].ant.type === 1 && !view[5].ant && !view[5].food && !view[3].ant) return {cell: 5, type: 2};
      }

      //If food is orthogonal to Queen, stay put
      if (view[1].food || view[3].food || view[5].food || view[7].food) return {cell: 4};

      //Look for guiding type 1 ant, try to move diagonally
      else if (view[7].ant && view[7].ant.friend && view[7].ant.type === 1 && !view[6].ant) return {cell: 6};
      else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 1 && !view[8].ant) return {cell: 8};
      else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 1 && !view[0].ant) return {cell: 0};
      else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 1 && !view[2].ant) return {cell: 2};
    }
  default: return {cell: 4};
}

이 개미는 Dave의 법의학 개미 와 비슷한 개념으로 작동합니다 . 그러나 대각선 방향으로 이동하고 3 개의 그룹으로 이동합니다.

1 단계 : 음식 출격

여왕 개미는 음식 한 조각이 보일 때까지 대각선으로 움직입니다. 그것은 Romanesco Road 와 비슷한 개념을 사용 하여 여왕을 뒤덮은 색상 흔적이 어떤 방법으로 앞으로 나아갈 수 있는지 알려줍니다.

2 단계 : 개미 2 개

여왕은 새로운 타입 1 "가이 딩"개미를 만들어 여왕과 함께 대각선으로 움직입니다. 그들은 각자 자신의 파트너에 비해 어느 쪽이 앞으로 나아갈 지 알아냅니다.

3 단계 : 강압

여왕과 그녀의 파트너가 음식 한 조각을 찾으면 여왕은이 음식을 사용하여 2 형 개미를 만듭니다. 이 개미에는 여왕을 따르기위한 구체적인 지시 사항과 태그도 있습니다. 이것은 대각선으로 움직이는 3 개의 개미 줄을 만들어 음식을 얻는 데 매우 빠릅니다.

자전

유형 2 개미가 음식으로 이동하는 것을 발견하면 대신에 유형 1 개미가 있던 다른 방향으로 이동합니다. 이것은 모든 개미가 이동하는 방향을 회전시킬 것이므로 개미가 시작점으로 다시 포장 될 가능성이 매우 낮아야한다는 것을 의미합니다.

참고 : 어떤 이유로 (다른 개미와 충돌 할 수 있습니까?) 유형 2 개미가 유형 1 개미보다 먼저 태어 났을 경우,이 회전으로 인해 유형 2 개미가 유형 1 개미 위로 이동하려고합니다. 이 문제를 해결하기 위해, 타입 2 개미가 대신 남겨두고 여왕이 또 다른 타입 2 개미를 만들게했습니다.


실험 중 음식을 찾을 때 무작위로 방향을 바꾸는 것이 무한한 포장을 피하는 데 매우 효과적이라는 것을 알았습니다. 새로운 발걸음을 내딛는 모든 단계의 기회를 줄이지 만 여기서 유용 할 수 있습니까?
Dave

@ 방향을 바꾸는 것에 대한 부분을 이해해야합니다. 내 직원 중 하나를 잃지 않고 방향을 바꿀 수있는 방법을 찾을 수 있다면이 아이디어는 분명히 효과가 있습니다. 그렇지 않다면, 나는 노동자 뒤를 떠날 때를 나타내는 표식으로 색을 입히고 여왕이 방향을 바꾸도록 노력할 것입니다.
K Zhang

@trichoplax 당신은 실격에서 사용 된 종자와 아군 수를 알고 있습니까? 그 문제를 일으킨 상황을 아는 것이 매우 유익 할 것입니다.
K Zhang

@trichoplax Nevermind, 방금 가서 위생 검사를 추가했습니다. 더 이상 실격되지 않습니다.
K Zhang

테스트를 위해 시드를 사용할 수 있습니다.이 경우 시드를 다시 실행하면 문제가 발생한 경우 어떻게되었는지 정확하게 확인할 수 있지만 모든 게임에서 동일한 결과를 얻을 수 있으므로 순위표에는 좋지 않습니다. 순위표 토너먼트는 시드 무작위 체크 박스에 틱없이 실행됩니다. 즉, 암호 화폐를 사용하여 가능한 한 공정하게 만듭니다.
trichoplax

5

메두사

function clean(move) {
    if (move["color"] == undefined) {
        if (view[move["cell"]].ant != null) {
            move = {
                cell: 4
            }
        }
        if (move["type"] == undefined) {
            if (view[4].ant.type == 5 && move["cell"] != 4 && view[move["cell"]].color > 2) {
                move["color"] = 1
            }
            if (view[move["cell"]].food == 1 && view[4].ant.type < 5 && view[4].ant.food > 0) {
                move = {
                    cell: 4
                }
            }
        } else if (view[4].ant.type != 5 || view[4].ant.food == 0 || view[move["cell"]].food != 0) {
            move = {
                cell: 4
            }
        }
    }
    return move
}

function coord(cell) {
    var x = (cell % 3) - 1
    var y = 1 - (cell - (cell % 3)) / 3
    return {
        x: x,
        y: y
    }
}

function getcell(x, y) {
    return (x + 1) + (1 - y) * 3
}

var diags = [0, 2, 8, 6]

var colorcounts = [0, 0, 0, 0, 0, 0, 0, 0, 0];
for (var i = 0; i < 9; i++) {
    colorcounts[view[i].color]++
}

var queen = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 5) {
        queen = i
    }
}

var guard = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 1) {
        guard = i
    }
}

var forager = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 2) {
        forager = i
    }
}

var black = -1
for (var i = 0; i < 9; i++) {
    if (view[i].color == 8) {
        black = i
    }
}

var yellow = -1
for (var i = 0; i < 9; i++) {
    if (view[i].color == 2) {
        yellow = i
    }
}


if (view[4].ant.type == 5) {
    if (forager >= 0 && view[forager].color == 8) {
        return clean({
            cell: forager,
            color: 2
        })
    }

    if (guard == -1) {
        if (view[4].color == 3) {
            if (view[4].ant.food > 1) {
                return clean({
                    cell: 0,
                    type: 2
                })
            }
            return clean({
                cell: 0,
                type: 1
            })
        }
        if (view[4].ant.food >= 3) {
            return clean({
                cell: 4,
                color: 3
            })
        }
        if (view[4].color == 1) {
            return clean({
                cell: 4,
                color: 2
            })
        }
        for (var i = 0; i < 9; i++) {
            if (view[i].food == 1) {
                return clean({
                    cell: i
                })
            }
        }
        for (var i = 0; i < 4; i++) {
            if (view[diags[i]].color != 2 && view[diags[(i + 2) % 4]].color == 2) {
                return clean({
                    cell: diags[i]
                })
            }
        }
        return clean({
            cell: 0
        })
    }

    var state = 3
    var max = 0
    for (var i = 3; i <= 4; i++) {
        if (colorcounts[i] > max) {
            max = colorcounts[i]
            state = i
        }
    }

    if (state == 3) {
        if (black >= 0 && forager == -1) {
            return clean({
                cell: black,
                type: 2
            })
        }
        if (forager >= 0 && view[forager].color != 2) {
            return clean({
                cell: 0,
                color: 8
            })
        }
        if (colorcounts[3] == 9) {
            return clean({
                cell: 4,
                color: 4
            })
        }
    }
    if (state == 4) {
        if (colorcounts[4] == 9) {
            return clean({
                cell: 4,
                color: 3
            })
        }
    }
    return clean({
        cell: 4
    })
}
if (view[4].ant.type == 1) {
    var dest = 0
    var destmap = [1, 0, 1, 1, 4, 1, 7, 8, 7]
    dest = destmap[queen]
    if (view[queen].color != view[dest].color && (view[queen].color == view[4].color || view[4].color == view[dest].color)) {
        if (queen < 4 && view[dest].color > 2 && view[dest].color < 5) {
            return clean({
                cell: queen,
                color: view[dest].color
            })
        }
        return clean({
            cell: dest,
            color: view[queen].color
        })
    }
    return clean({
        cell: dest
    })
}
if (view[4].ant.type == 2) {
    if (queen >= 0 && view[4].color == 8) {
        return clean({
            cell: 4
        })
    }
    var state = 3
    var max = 0
    for (var i = 5; i <= 7; i++) {
        if (colorcounts[i] > max) {
            max = colorcounts[i]
            state = i
        }
    }
    var flowx = 0
    var flowy = 0
    for (var i = 0; i < 9; i++) {
        for (var j = i + 1; j < 9; j++) {
            var loci = coord(i)
            var locj = coord(j)
            var dx = locj.x - loci.x
            var dy = locj.y - loci.y
            var cyc = 0
            if (view[i].color >= 5 && view[i].color <= 7 && view[j].color >= 5 && view[j].color <= 7) {
                var cyc = ((view[j].color - view[i].color) % 3 + 3) % 3
                if (cyc == 2) {
                    cyc = -1
                }
            } else if (view[i].color >= 5 && view[i].color <= 7) {
                cyc = 0.1
            } else {
                cyc = -0.1
            }
            flowx += cyc * dx / (dx * dx + dy * dy)
            flowy += cyc * dy / (dx * dx + dy * dy)

        }
    }
    if (flowx * flowx > flowy * flowy) {
        flowy = 0
    } else {
        flowx = 0
    }
    if (flowx < 0) {
        flowx = -1
    }
    if (flowy < 0) {
        flowy = -1
    }
    if (flowx > 0) {
        flowx = 1
    }
    if (flowy > 0) {
        flowy = 1
    }
    if (queen >= 0) {
        var locq = coord(queen)
        flowx = -locq.x
        flowy = -locq.y
        state = 5
    }
    if (view[4].ant.food > 0) {
        if (guard >= 0) {
            var destmap = [1, 0, 1, 1, 4, 1, 7, 8, 7]
            return clean({
                cell: destmap[guard]
            })
        }
        dest = getcell(-flowx, -flowy)
        if (dest != 7) {
            dest = 1
        }
        if (view[dest].color >= 5 && view[dest].color <= 7) {
            return clean({
                cell: dest
            })
        }
        if (view[dest - 1].color >= 5 && view[dest - 1].color <= 7) {
            return clean({
                cell: dest - 1
            })
        }
        return clean({
            cell: 4
        })
    }
    if (view[4].color >= 5 && view[4].color <= 7) {
        state = view[4].color
    }
    var nextc = ((state - 4) % 3 + 5)
    var prevc = ((state - 3) % 3 + 5)
    var centerdest
    centerdest = getcell(flowx, flowy)
    if (view[centerdest].color != state && view[centerdest].color != nextc) {
        return clean({
            cell: centerdest,
            color: nextc
        })
    }
    for (var dest = 1; dest < 9; dest++) {
        var locd = coord(dest)
        var net = locd.x * flowx + locd.y * flowy
        if (net > 0 && view[dest].color != view[centerdest].color) {
            return clean({
                cell: dest,
                color: view[centerdest].color
            })
        }
    }
    for (var dest = 0; dest < 9; dest++) {
        if (view[dest].food == 1) {
            if (view[dest].color >= 5 && view[dest].color <= 7) {
                return clean({
                    cell: dest
                })
            }
            return clean({
                cell: dest,
                color: state
            })
        }
    }
    if (centerdest == 4 && view[0].color >= 5 && view[0].color <= 7) {
        return clean({
            cell: 0
        })
    }
    if (centerdest > 0 && view[centerdest - 1].color >= 5 && view[centerdest - 1].color <= 7) {
        return clean({
            cell: centerdest - 1
        })
    }
    return clean({
        cell: centerdest
    })
}

이 봇은 좋지는 않지만 미래의 개미 봇에 포함될 몇 가지 멋진 전략을 사용합니다. 그 이름은 식민지가 게임 보드에서 만드는 모양에서 유래합니다.

메두사 행동

1 단계 : 초기 투자

여왕은 식민지를 시작하기에 충분한 음식 3 개를 집어들 때까지 대각선으로 똑바로 움직입니다. 일단 조각이 쌓이면 정착지 (정지 여왕이 됨)가되어 2 명의 마초를 만들고 1 명의 경비원을 만듭니다. 전략의 흥미로운 부분으로, 보호 개미의 존재 자체가 다음 단계를 유발하고 여왕이 다시 움직이지 못하게하는 것입니다.

2 단계 : 식민지화

여기서 세 가지 유형의 개미는 다른 역할을합니다.

여왕은 경비원의 도움으로 두 주 사이에서 천천히 진동합니다. 현재 상태는 새로 획득 한 식품이 노동자로 전환 될지 여부를 결정하는 것이므로 식량의 약 50 %가 식민지에 재투자됩니다. 퀸을 포함하는 전체 3x3 영역은 상태를 저장하는 데 사용되므로 삭제를 취소하고 상태를 복구 할 수 있습니다.

가드

경비원은 자신의 전 생애를 여왕과 인접하여 무작위로 돌며 살아갑니다.

경비원은 여왕의 상태를 유지하는 데 중요한 역할을합니다. 퀸의 3x3 영역에서 오류를 수정하려고 시도합니다. 해당 영역에 두 개의 유효한 대체 색상이있는 경우 두 색상 중 "보정 된"상태가되는 것은 비교적 임의적입니다. 그러나 합의에 도달하면 여왕은 광장을 반대 색으로 뒤집어 프로세스를 다시 시작합니다. 이것이 여왕의 상태를 진동시키는 원인이며 매우 오류에 강한 방식으로 이루어집니다.

경비원은 또한 여왕의 "궁전"의 문지기 역할을합니다. 위조자가 경비병을 보았을 때 여왕이 가시 범위를 벗어난 경우에도 여왕 옆으로 움직일 수 있습니다.

마초

마초는 식민지를 떠날 때 주기적으로 적 녹청 패턴을 배치하고 음식을 운반 할 때 거꾸로 따릅니다. 그들은 경로가 너무 엉키지 않고 일부 세포가 손상 되더라도 길을 찾을 수 있도록 정말로 넓은 경로가 필요하기 때문에 상당히 상당한 영역을 칠하게됩니다 .

위조자의 일반적인 경로 :

위조 경로

보통 직선으로 이동하지만 때로는 90도 회전하는 방식에 주목하십시오. 이것은 내려 놓을 때 자체 경로 내에서 무작위로 걷는 방식의 결과입니다.


나는 트레일 소거가 마초를 물리 칠 수 있을지 궁금하다. 블랙홀에 대항 할 때 알 수 있듯이 넓은 경로를 지우는 데 좋습니다.
pppery

@ppperry 가끔 그렇습니다.
PhiNotPi

r-> b-> g-> r 주기만 이동하여 근로자를보다 효율적으로 복귀시킬 수 있습니까?
CalculatorFeline

@ trichoplax 나는 그것이 허용되지 않는 것을 깨닫지 못했습니다. 어쨌든 지금 수정되었습니다.
PhiNotPi

"실격"아래에있었습니다 : "작업자를 생산하는 세포가 비어 있지 않습니다." 하지만 지금은 좀 더 명확하게하기 위해 사양을 편집했습니다. "작업자를 생성하는 셀이 비어 있지 않습니다 (음식 또는 개미 포함)."
trichoplax

5

브라운 지그

이 플레이어는 노동자를 생산하지 않으며 여왕은 무작위로 움직입니다. 랜덤 모션은 퀸이 매번 같은 방향을 반환하기 때문에 입력 가시적 셀은 매 움직임마다 임의의 방향으로 표시되어 움직임이 직선으로되지 않도록합니다.

답변의 첫 번째 코드 블록은 게임에 자동으로 포함됩니다.

// Full version that won't be disqualified for moving onto another ant

// Move to food if visible
for (var i=0; i<9; i+=1) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (var i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise one of the vertical or horizontal cells if not occupied
for (var i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise don't move at all
return {cell:4}

다음은 다른 개미를 확인하지 않지만 다른 개미를 밟기 위해 실격 될 때까지 동일한 동작을하는 더 간단한 버전입니다.

// Basic version for an intuitive understanding

// Move to food if visible
for (var i=0; i<9; i+=1) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move "up and left", which will be a random direction
return {cell:0}

이 두 번째 코드 블록은 게임에서 선택되지 않습니다. 즉, 답변 설명의 일부로 추가 코드 블록을 포함 할 수 있습니다. 게임에서 경쟁하려는 코드 블록이 답의 첫 번째 코드인지 확인하십시오.

입력의 임의 방향에도 불구하고 직선 이동을 생성하는 예는 Romanesco Road를 참조하십시오 .


왜 색상을 표시해야합니까?
Solomon Ucko

1
좋은 질문. 이것은 사람들에게 규칙을 고르는 데 도움이 될만한 첫 번째 대답입니다. 단순히 색상을 표시하지 않음으로써 두 배 높은 점수를 얻을 수 있지만, 예를 들어 이해를 돕기 위해 경로가 명확하게 표시되기를 원했습니다.
trichoplax

알겠습니다.
솔로몬 유코

불필요하고 중복되는 산만했기 때문에 이제 색상 표시를 제거하도록 편집했습니다. 여왕은 이제 보이는 경우 음식으로 이동하고 더 많은 땅을 덮기 위해 대각선 이동을 선호합니다. 색상이 전혀 사용되지 않습니다.
trichoplax

4

라라 인 블레

var Queen = 5;
var QueenTrail = [];
var EnemyAnts = [];
var EnemyColors = [];
var QueenTrailColor = 7;
var QueenTrailColor2 = 8;
var QueensPosition = -1; //Future use...

var rotations =   
[ 0,1,2,
  3,4,5,
  6,7,8,

  6,3,0,
  7,4,1,
  8,5,2,

  8,7,6,
  5,4,3,
  2,1,0,

  2,5,8,
  1,4,7,
  0,3,6];

var moves = [];
getMoves();
return findBestMove();

function getMoves()
{
    var matchIdx = -1;
    //Initialization of current state
    for(ii = 0; ii < 9; ii++)
    {
        if(ii != 4)
        {
            if(view[ii].color == QueenTrailColor)
            {
                QueenTrail.push(ii);
            }
            else if(view[ii].color == QueenTrailColor2)
            {
                QueenTrail.push(ii);
            }
            else if(view[ii].color != 1)
            {
                EnemyColors.push(ii);
            }
        }

        if(ii != 4 && view[ii].ant != null)
        {
            if(view[ii].ant.friend)
            {
                if(view[ii].ant.type == Queen)
                {
                    QueensPosition = ii * ii;
                }
            }
            else
            {
                EnemyAnts.push(ii);
            }
        }
    }

    switch (view[4].ant.type) 
    {
        case Queen:
        {        
            //first get the food
            for (var ii = 0; ii < 9; ii++) 
            {
                if (view[ii].food > 0 && view[ii].ant == null) 
                {
                    moves.push(getCell(ii)) ;
                }
            }
            if(EnemyAnts.length == 0)
            {
                lm(AA(-QueenTrailColor),AA(4), {cell:4, color:QueenTrailColor});
            }

            if(QueenTrail.length >= 5 || EnemyAnts.length > 0)
            {
                lm(AA(-QueenTrailColor), AA(0,1,2),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,5),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,6),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,6),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,5,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(1,2,7),{cell:1});
                lm(AA(-QueenTrailColor), AA(1,3,5),{cell:1});
                lm(AA(-QueenTrailColor), AA(0,1),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,5),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(1,3),{cell:1});
                lm(AA(-QueenTrailColor), AA(1,7),{cell:1});
            }
            if(QueenTrail.length == 4)
            {
                lmQT(AA(0,1,2,3),{cell:7});
                lmQT(AA(0,1,2,5),{cell:7});
                lmQT(AA(0,1,2,6),{cell:7});
                lmQT(AA(0,1,2,7),{cell:5});
                lmQT(AA(0,1,2,8),{cell:7});
                lmQT(AA(0,1,3,5),{cell:7});
                lmQT(AA(0,1,3,7),{cell:8});
                lmQT(AA(0,1,3,8),{cell:2});
                lmQT(AA(0,1,5,6),{cell:8});
                lmQT(AA(0,1,5,7),{cell:6});
                lmQT(AA(0,1,5,8),{cell:3});
                lmQT(AA(0,1,6,7),{cell:8});
                lmQT(AA(0,1,6,8),{cell:2});
                lmQT(AA(0,1,7,8),{cell:2});
                lmQT(AA(0,2,3,7),{cell:8});
                lmQT(AA(0,2,3,8),{cell:6});
                lmQT(AA(0,2,6,8),{cell:1});
                lmQT(AA(0,3,5,7),{cell:2});
                lmQT(AA(0,3,5,8),{cell:2});
                lmQT(AA(1,3,5,7),{cell:0});
            }
            if(QueenTrail.length == 1)
            {                
                lmQT(AA(0), {cell:8});
                lmQT(AA(1), {cell:7});
            }
            else if(QueenTrail.length == 0)
            {
                moves.push(getCell(1));
            }

            if(QueenTrail.length == 0) // starting out or someone is messing with us
            {
                moves.push( getCellColor(1, QueenTrailColor));
            }    
            else if (QueenTrail.length >= 5) //queen is stuck? move her randomly until we get a straight trail
            {    
                moves.push( getCellColor(1, QueenTrailColor2));
            }
            else if (QueenTrail.length >= 3)
            {
                lmQT(AA(0,1,2),{cell:3});
                lmQT(AA(0,1,3),{cell:7});
                lmQT(AA(0,1,5),{cell:3});
                lmQT(AA(0,1,6),{cell:7});
                lmQT(AA(0,1,7),{cell:3});
                lmQT(AA(0,1,8),{cell:3});
                lmQT(AA(0,2,3),{cell:6});
                lmQT(AA(0,2,6),{cell:3});
                lmQT(AA(0,2,7),{cell:1});
                lmQT(AA(0,3,7),{cell:8});
                lmQT(AA(0,3,8),{cell:5});
                lmQT(AA(0,5,7),{cell:6});
                lmQT(AA(1,2,7),{cell:0});
                lmQT(AA(1,3,5),{cell:6});
            }
            else if(QueenTrail.length == 2)
            {
                lmQT(AA(0,1),{cell:7});
                lmQT(AA(0,2),getCellColor(1, QueenTrailColor));
                lmQT(AA(0,3),{cell:6});
                lmQT(AA(0,5),{cell:1});
                lmQT(AA(0,7),{cell:3});
                lmQT(AA(0,8),{cell:3});
                lmQT(AA(1,3),{cell:6});
                lmQT(AA(1,7),{cell:0});
            }
            else if(QueenTrail.length == 1) //we are either going in a straight line or trapped?
            {    
                if(view[4].ant.food > 0)
                {
                    lmQT(AA(0), getCell(0));
                    //clear out the area for the ants
                    if(EnemyColors.length > 0)
                    {
                        moves.push( getCellColor(EnemyColors[0],1));
                    }
                }
                lmQT(AA(0), getCell(8));
                lmQT(AA(1), getCell(7));
                lmQT(AA(2), getCell(6));
            }
            break;
        }
    }
    moves.push( getCell(4));
}

function leftOfPos(x)
{
    if (x == 0)
    {
        return 3;
    }
    else if (x == 1)
    {
        return 0;
    }
    else if (x == 2)
    {
        return 1;
    }
    else if (x == 3)
    {
        return 6;
    }
    else if (x == 5)
    {
        return 2;
    }
    else if (x == 6)
    {
        return 7;
    }
    else if (x == 7)
    {
        return 8;
    }
    else if (x == 8)
    {
        return 5;
    }
}

function findBestMove() 
{
    var keeper = 0;
    for(var ii = 0; ii < moves.length ; ii++)
    {
        if(moves[ii].cell < 0 || moves[ii].cell > 8 || (moves[ii].cell != 4 && (moves[ii].color == null || moves[ii].color == 0) && view[moves[ii].cell].ant != null) || (view[moves[ii].cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) 
        {
            continue;
        }
        else if(moves[ii].type != null && (view[moves[ii].cell].ant != null || view[moves[ii].cell].food > 0 || view[0].color == 1)) //semi random here. 
        {
            continue;
        }
        else
        {
            keeper = ii;
            break;
        }
    }
    return moves[keeper];
}

function lm(matchingColors, coords, matchCell)
{
    var matchTarget = coords.length ;
    var matchCount = [0,0,0,0];
    var returnVal = -1;
    for(var ii = 0; ii < coords.length; ii++)
    {        
        for(var jj = 0; jj < 4; jj++)
        {
            var actualIndex = rotations[coords[ii] + (jj * 9)];
            var foundMatch = false;
            for(var kk = 0; kk < matchingColors.length; kk++)
            {
                var matchingColor = matchingColors[kk];

                if(matchingColor >= 1 && matchingColor <= 8 && view[actualIndex].color == matchingColor)
                {
                    foundMatch = true;
                    break;
                }    
                else if(matchingColor < 0 && view[actualIndex].color != -matchingColor)
                {
                    foundMatch = true;
                    break;
                }
            }
            if(foundMatch)
            {
                matchCount[jj] = matchCount[jj] + 1;
                if(matchCount[jj] == matchTarget)
                {
                    matchCell.cell = rotations[matchCell.cell + (jj * 9)];
                    moves.push(matchCell);
                    returnVal = jj;
                }
            }
        }
    }
    return returnVal;
}

function lmQT(coords, matchCell)
{
    return lm(AA(QueenTrailColor, QueenTrailColor2), coords,matchCell);
}

function AA()
{
    return arguments;
}

function getCell(x)
{
    return {cell:x};
}

function getCellColor(x, y)
{
    return {cell:x, color:y};
}

파란 여왕은 파란 흔적을 남기고, 검은 색을 피하고 '고정'되면 검은 부스러기를 남깁니다.

그녀는 4 개의 회전을 모두 사용하여 특정 파란색 / 검정색 "모양"을 찾고 잠재적 움직임 목록을 만듭니다. 실격 처리가 제거되고 단일 결과가 선택됩니다. 여왕은 다소 예측 가능하지만 특정 모양은 임의성을 유발합니다. 그녀는 방향이 바뀔 수 있다는 사실 때문에 음식을 찾은 후 방향을 바꿀 것입니다.


3
사이트에 오신 것을 환영합니다! :)
DJMcMayhem

여기있는 것이 좋습니다!
일부 러너 녀석

4

FireFlyMkII

입력이 완료 될 때까지이 코드는 java에서 수행중인 마스터 개발 소스에서 코드가 변환 될 때 추악합니다.

    // maps current view's cells' indecies to the rotated cell's location's indecies for each direction
    var rotate = 
            [[0,1,2,3,4,5,6,7,8],
             [2,5,8,1,4,7,0,3,6],
             [8,7,6,5,4,3,2,1,0],
             [6,3,0,7,4,1,8,5,2]];

    // the colours that form the pattern of the trail back to the queen
    var TRAIL_COLOR_A = 8;
    var TRAIL_COLOR_B = 2;
    var TRAIL_COLOR_C = 5;
    var trailColours = [TRAIL_COLOR_A,TRAIL_COLOR_B,TRAIL_COLOR_C];
    var trailColoursLookUp = [-1,-1,1,-1,-1,2,-1,-1,0];

    var ORIENTATION_MARKER = 8;

    // Queens Modes
    var QUEEN_MODE_HUNTING_MOVING = 6;
    var QUEEN_MODE_HUNTING_PAINTING = 1;
    var QUEEN_MODE_RESETTING = 5;
    var QUEEN_MODE_RESETTING_SPAWNING = 3;
    var QUEEN_MODE_COUNTING_EVEN = 7;
    var QUEEN_MODE_COUNTING_ODD = 4;
    var QUEEN_MODE_NESTING = 2;

    // the number of non-blank (i.e. not colour 1 ) colours to used to encode the queen's worker spawn counter. Min of 1. Max of 7
    var SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT = 7;


    // the maximum number that can be encoded using the queen's worker spawn counter
    var SPAWN_COUNTER_MAX = SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT*SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT*SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT -1;//SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT * SPAWN_COUNTER_USED_CELLS_COUNT_MAX;

    // the minimum game ticks between spawning a worker. Min of 0, Max of SPAWN_COUNTER_MAX
    var TICKS_BETWEEN_FOOD_RETURN_MAX = 50;

    // No Operation... i.e. stay put do nothing
    var NO_OP = {cell:4};

    var ANT_TYPE_WORKER = 1; 
    var ANT_TYPE_QUEEN = 5;

    var orientationMarkerRotation = -1;

    var i=0;
    var j=0;

    // returns true of the provided colour is a trail colour
function isTrailColour(colour)
    {
        return colour === trailColours[0] || colour === trailColours[1] || colour === trailColours[2];
    }

    // returns the colour of the colour in the trail away from queen
function nextTrailColor(currentTrailColour)
    {
        return trailColours[(trailColoursLookUp[currentTrailColour]+1)%3];
    }

    // returns the colour of the colour in the trail toward from queen
function prevTrailColor(currentTrailColour)
    {
        return trailColours[(3+trailColoursLookUp[currentTrailColour]-1)%3];
    }

    // RNG
function randomNumberGenerator(seed)
    {
        return (1103515245 * seed + 12345) % 2147483647;
    }

    // returns a positive random integer based on the provided ant's view and seed
function randomInt(view,seed)
    {
        for (var i=0;i<9;i++)
        {
            if (view[i].ant !=null)
            {
                seed=randomNumberGenerator(seed+view[i].ant.food);
                seed=randomNumberGenerator(seed+view[i].ant.type);
                seed=randomNumberGenerator(seed+(view[i].ant.friend?1:0));
            }
            seed=randomNumberGenerator(seed+view[i].color);
            seed=randomNumberGenerator(seed+view[i].food);
        }
        return seed<0?-seed:seed;
    }

    // SHUFFLE *NOT* IMPLEMENTED 
function shuffleIndecies(view,seed,range)
    {
        var indecies = new Array(range);

        for (var i=0;i<range;i++)
        {
            indecies[i]=i;
        }

        return indecies;
    }

function processOrientation(view)
    {
        // count orientation markers
        var orientationMarkerCount = 0;
        for (var i=0; i<rotate.length;i++)
        {
            if (view[rotate[i][1]].color === ORIENTATION_MARKER)
            {
                orientationMarkerCount++;
                orientationMarkerRotation = i;
            }
        }

        // corruption detected
        if (orientationMarkerCount >1)
        {
            return {cell:4, color: QUEEN_MODE_RESETTING};
        }

        // place the orientation marker
        if (orientationMarkerCount === 0)
        {
            return {cell:1, color: ORIENTATION_MARKER};
        }
        return null;
    }

function incrementSpawnCounter(view)
    {
        var action = processOrientation(view);
        if (action != null)
        {
            return action;
        }

        var newCount = decodeThreeCellsToInt(view) + 1;

        var MSD = view[rotate[orientationMarkerRotation][3]].color-1;
        var NSD = view[rotate[orientationMarkerRotation][7]].color-1;
        var LSD = view[rotate[orientationMarkerRotation][5]].color-1;

        var MSDisEven =(MSD & 1) ===0;
        var NSDisEven =(NSD & 1) ===0; 

        var MSDdelta =  Math.floor(newCount / 49) - MSD;
        var NSDdelta =  (MSDisEven ? Math.floor(Math.floor(newCount%49)/7) :( 6 - Math.floor(Math.floor(newCount%49)/7))) - NSD;
        var LSDdelta =  (((MSDisEven && NSDisEven) || (!MSDisEven && !NSDisEven)) ? Math.floor(newCount%7) :( 6 - Math.floor(newCount%7))) - LSD;

        // check for roll over 
        if (MSDdelta > 6)
        {
            return {cell:rotate[orientationMarkerRotation][3], color:1};
        }

        // Most Significant Digit (cell) update
        if (MSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][3], color:(MSD+MSDdelta)+1};
        }

        // Next Significant Digit (cell) update
        if (NSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][7], color:(NSD+NSDdelta)+1};
        }

        // Least Significant Digit (cell) update
        if (LSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][5], color:(LSD+LSDdelta)+1};
        }

        return null;
    }

function decodeThreeCellsToInt(view)
    {
        var MSD = view[rotate[orientationMarkerRotation][3]].color-1;
        var NSD = view[rotate[orientationMarkerRotation][7]].color-1;
        var LSD = view[rotate[orientationMarkerRotation][5]].color-1;

        var MSDisEven =(MSD & 1) ===0;
        var NSDisEven =(NSD & 1) ===0; 
        return MSD * 49 + 
               (MSDisEven?NSD:6-NSD) * 7 + 
               ((MSDisEven && NSDisEven) || (!MSDisEven && !NSDisEven)?LSD:6-LSD);
    }
    // Performs a paint command to reset the queen's worker spawn counter to 0.
    // NOTE that is may take multiple calls on sequential game ticks to complete the reset.
    // returns null if the counter is reset
function resetSpawnCounter(view)
    {
        var orientationMarkerCount = 0;
        for (i=1; i<9; i+=2) 
        {
            if (view[i].color === ORIENTATION_MARKER && orientationMarkerCount ===0)
            {
                orientationMarkerCount++;
            }
            else if (view[i].color!=1)
            {
                return {cell:i, color:1};
            }
        }

        // place the orientation marker
        if (orientationMarkerCount === 0)
        {
            return {cell:1, color: ORIENTATION_MARKER};
        }

        return null;
    }


function spawnNewWorker(view,type,defaultAction)
    {
        // ensure that we do not try and create a worker when having no food
        if (view[4].ant.food > 0)
        {
            // now try to spawn an ant
            if (view[1].ant===null && view[1].food===0)
            {
                return {cell:1, type:type};
            }

            // previous spawn cell was blocked, try another 
            if (view[3].ant===null && view[3].food===0)
            {
                return {cell:3, type:type};
            }

            // previous spawn cell was blocked, try another
            if (view[5].ant===null && view[5].food===0)
            {
                return {cell:5, type:type};
            }

            // previous spawn cell was blocked, try another
            if (view[7].ant===null && view[7].food===0)
            {
                return {cell:7, type:type};
            }
        }
        return defaultAction;
    }

function isCellTrailToQueen(cell,currentAntCellColour)
    {
        // is cell containing our queen, or is the cell the next cell colour on the trail back
        return (cell.ant!=null && cell.ant.friend && cell.ant.type === ANT_TYPE_QUEEN) ||
                cell.color === prevTrailColor(currentAntCellColour);
    }

    // entry point into ant logic
function getAction(view)
    {
        var random = 1;
        var food = view[4].ant.food;
        var currentCellColour = view[4].color;

/////////////////////////////////////// QUEEN ///////////////////////////////////////
        if (view[4].ant.type === ANT_TYPE_QUEEN)
        {
            // move to visible food. this queen is greedy!
            for (i=0; i<9; i++) 
            {
                if (view[i].food>0) {
                    return {cell:i};
                }
            }

            // see if we have spawned a worker in the last few turns
            var workerSpawned = false;
            // look in orthogonal cells
            for (i=1; i<9; i+=2) 
            {
                // ant detected and is friendly and of worker type
                if (view[i].ant !=null && view[i].ant.friend && view[i].ant.type===ANT_TYPE_WORKER)
                {
                    workerSpawned=true;
                    break;
                }
            }

            var queenMode = currentCellColour;
            var foodModRemainder=1;

            var minFoodLatch = 0;
            if (food>=500) minFoodLatch = 500;
            else if (food>=400) minFoodLatch = 400;
            else if (food>=300) minFoodLatch = 300;
            else if (food>=200) minFoodLatch = 200;
            else if (food>=100) minFoodLatch = 100;
            else if (food>=50) minFoodLatch = 50;
            else if (food>=20) minFoodLatch = 30;
            else if (food>=20) minFoodLatch = 20;
            else if (food>=10) minFoodLatch = 10;
            else if (food>=5) minFoodLatch = 5;

            switch (queenMode)
            {
                case QUEEN_MODE_HUNTING_MOVING:
                {


                    // move to the cell mirror of the trail cell
                    for (i=0; i<9; i++) {
                        if (view[i].ant===null && view[i].color===QUEEN_MODE_HUNTING_MOVING) {
                            if (view[8-i].ant==null)
                            {
                                return {cell:8-i};
                            }
                        }
                    }

                    // Otherwise move to one of the diagonal cells if not occupied
                    for (i=0; i<9; i+=2) 
                    {
                        if (view[i].ant===null) 
                        {
                            return {cell:i};
                        }
                    }

                    // Otherwise move to one of the vertical or horizontal cells if not occupied
                    for (i=1; i<9; i+=2)
                    {
                        if (view[i].ant===null)
                        {
                            return {cell:i};
                        }
                    }
                    return {cell:4};
                }
                case QUEEN_MODE_HUNTING_PAINTING:
                {
                    // no food found, change to move mode
                    if (food ===0)
                    {
                        // Queenie places a trail
                        return {cell:4, color:QUEEN_MODE_HUNTING_MOVING};
                    }
                    // found food, now change to nesting mode
                    else
                    {
                        return {cell:4, color:QUEEN_MODE_NESTING};
                    }
                }

                // initialise colony
                case QUEEN_MODE_NESTING:
                {
                    // we have spawned a worker so change to counting mode
                    if (workerSpawned===true)
                    {
                        return {cell:4, color:QUEEN_MODE_COUNTING_ODD};
                    }

                    var action = processOrientation(view);
                    if (action != null)
                    {
                        return action;
                    }

                    // ensure that we have the initial band constructed around the queen
                    for (i=0; i<9; i+=2) 
                    {
                        if (i!=4 && view[i].color!=TRAIL_COLOR_A)
                        {
                            return {cell:i, color:TRAIL_COLOR_A};
                        }
                    }

                    // ensure that the counter cells are reset.
                    action = resetSpawnCounter(view);
                    if (action != null)
                    {
                        return action;
                    }

                    // spawn initial worker
                    return spawnNewWorker(view, ANT_TYPE_WORKER, NO_OP);
                }


                case QUEEN_MODE_RESETTING_SPAWNING:

                    // spawn the worker if we have not spawned a worker in the last few turns 
                    if (!workerSpawned===true)
                    {
                        return spawnNewWorker(view, ANT_TYPE_WORKER, NO_OP);
                    }
                    // must have spawned a worker previously, so reset the counter 
                    var action = resetSpawnCounter(view);

                    // still in process of resetting counter...
                    if (action != null)
                    {
                        return action;
                    }


                    // spawn counter as been reset. We will set the queen back to counting mode;
                    return {cell:4, color:food%2===0?QUEEN_MODE_COUNTING_EVEN:QUEEN_MODE_COUNTING_ODD};

                case QUEEN_MODE_RESETTING:

                    action = resetSpawnCounter(view);

                    // still in process of resetting counter...
                    if (action != null)
                    {
                        return action;
                    }


                    // spawn counter as been reset. We will set the queen back to counting mode;
                    return {cell:4, color:food%2===0?QUEEN_MODE_COUNTING_ODD:QUEEN_MODE_COUNTING_EVEN};

                case QUEEN_MODE_COUNTING_ODD:
                    foodModRemainder = 2;
                case QUEEN_MODE_COUNTING_EVEN:
                {
                    foodModRemainder--;

                    action = processOrientation(view);
                    if (action != null)
                    {
                        return action;
                    }

                    var spawnCounter = decodeThreeCellsToInt(view);

                    // repair any damage to the initial band constructed around the queen
                    for (i=0; i<9; i+=2) 
                    {
                        if (i!=4 && view[i].color!=TRAIL_COLOR_A)
                        {
                            return {cell:i, color:TRAIL_COLOR_A};
                        }
                    }

//                    // spawn interval time threshold as been reached and we have food to convert into workers...
//                    if (spawnCounter>=TICKS_BETWEEN_FOOD_RETURN_MAX && food>minFoodLatch)
//                    {
//                        // change to reset spawn counter mode to spawn a new worker
//                        return new Paint(4,QUEEN_MODE_RESETTING_SPAWNING);
//                    }
//
//                    // Check to see if a worker has just returned some food.
//                    if (food>0 && food%2 == foodModRemainder)
//                    {
//                        // change to reset spawn counter mode
//                        return new Paint(4,QUEEN_MODE_RESETTING);
//                    }

                    // Check to see if a worker has just returned some food.
                    if (food>0 && food%2 === foodModRemainder)
                    {

                        // spawn interval time threshold as been reached and we have food to convert into workers...
                        if (spawnCounter>=TICKS_BETWEEN_FOOD_RETURN_MAX && food>0)
                        {
                            // change to reset spawn counter mode to spawn a new worker
                            return {cell:4, color:QUEEN_MODE_RESETTING_SPAWNING};
                        }

                        // change to reset spawn counter mode
                        return {cell:4, color:QUEEN_MODE_RESETTING};
                    }


                    if (spawnCounter < SPAWN_COUNTER_MAX)
                    {
                        // simply increment the counter
                        return incrementSpawnCounter(view);
                    }

                    return NO_OP;
                }
                default:
                {
                }

            }


        }

/////////////////////////////////////// WORKER ///////////////////////////////////////



        var expectedNextPathColourToEdge = nextTrailColor(currentCellColour);

        // worker is looking for food
        if (food===0)
        {
/////////////////////////////////// WORKER HUNTNING //////////////////////////////////    

            // determine whether we are a recently spawned worker
            for (var i=1;i<9;i+=2)
            {
                // are we orthogonal to the queen?
                if (view[i].ant!=null && view[i].ant.friend && view[i].ant.type === ANT_TYPE_QUEEN)
                {
                    // test to see whether queen's counter has reset so worker is free to move
                    if (view[i].color === QUEEN_MODE_COUNTING_ODD || view[i].color === QUEEN_MODE_COUNTING_EVEN )
                    {
                        for (var j=1;j<9;j+=2)
                        {
                            if (view[j].ant===null && view[j].color===TRAIL_COLOR_A)
                            {
                                return {cell:j};
                            }
                        }
                    }
                    // wait until queen's counter has reset
                    return NO_OP;
                }
            }

//            // this is to try and unstick stuck ants... not overly well i might add
//            if (randomInt(view,1)%20==1)
//            {
//                // attempt to pick an empty random trail-cell
//                for (i = randomInt(view,666)%9;i>0;i--)
//                {
//                    if (view[i].ant==null && view[i].food==0 && isTrailColour(view[i].color))
//                    {
//                        return new Move(i);
//                    }
//                }
//            }

            // see if there is any food off band that is enclosed or almost enclosed by trail cells
            // if so, then move to claim the food
            if (view[1].food>0 &&
                isTrailColour(view[0].color) &&
                isTrailColour(view[2].color))
            {
                return {cell:1};
            }

            if (view[3].food>0 &&
                isTrailColour(view[0].color) &&
                isTrailColour(view[6].color))
            {
                return {cell:3};
            }

            if (view[5].food>0 &&
                isTrailColour(view[2].color) &&
                isTrailColour(view[8].color))
            {
                return {cell:5};
            }

            if (view[7].food>0 &&
                isTrailColour(view[6].color) &&
                isTrailColour(view[8].color))
            {
                return {cell:7};
            }


            // if not on trail, attempt see if cells surrounding are trail colours... and set our own cell accordingly
            if (!isTrailColour(currentCellColour))
            {
                for (var priority = 0; priority <4;priority++)
                {
                    // repeat for each rotation
                    var indecies = shuffleIndecies(view,random,4);
                    for (var j=0;j<4;j++)
                    {
                        var r = indecies[j];
                        switch(priority)
                        {
                        // C??  ...
                        // ???  .P.
                        // P?N  ...
                        case 0:
                            if (isTrailColour(view[rotate[r][0]].color) && 
                                nextTrailColor(view[rotate[r][0]].color) === view[rotate[r][8]].color &&
                                prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][6]].color};
                            }
                            break;

                        // ??C  ...
                        // ???  .C.
                        // N?C  ...
                        case 1:
                            if (isTrailColour(view[rotate[r][2]].color) && 
                                view[rotate[r][2]].color === view[rotate[r][8]].color &&
                                nextTrailColor(view[rotate[r][2]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][2]].color};
                            }
                            break;

                        // C??  ...
                        // ???  .C.
                        // P??  ...
                        case 2:
                            if (isTrailColour(view[rotate[r][0]].color) && 
                                prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][0]].color};
                            }
                            break;

                        // C??  ...
                        // ???  .C.
                        // ???  ...
                        case 3:
                            if (isTrailColour(view[rotate[r][0]].color))
                            {
                                return {cell:4, color: view[rotate[r][0]].color};
                            }
                            break;
                        }
                    }
                }
                // we are completely lost! lets perform a random walk and hopefully find the surface again
                return {cell:view[2].ant === null?2:4};
            }

            // decide worker action...
            for (var priority = 0; priority <13;priority++)
            {
                // repeat for each rotation
                var indecies = shuffleIndecies(view,random,4);
                for (var j=0;j<4;j++)
                {
                    var r = indecies[j];
                    var cellToMoveTo =-1;

                    switch(priority)
                    {
                    /////// AVOID MOVING/PAINTING LOCK-STEP ///////

                    // X?X  ...
                    // ?C?  .M.
                    // C?W  ...

                    case 0:
                        if (view[rotate[r][6]].color === currentCellColour &&
                            !isTrailColour(view[rotate[r][0]].color) &&
                            !isTrailColour(view[rotate[r][2]].color) &&
                            view[rotate[r][8]].ant!=null &&
                            view[rotate[r][8]].ant.type!=ANT_TYPE_QUEEN) 
                        {
                            // step back on path back to queen
                            return NO_OP;
                        }
                        break;

                    /////// REPAIR PATH ///////

                    // P?X  ..C
                    // ?C?  ...
                    // C??  ...

                    case 1:
                        if (view[rotate[r][2]].color != currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][0]],currentCellColour))
                        {
                            return {cell:rotate[r][2], color:currentCellColour};
                        }
                        break;

                    // ??C  N..
                    // ?C?  ...
                    // X?P  ...

                    case 2:
                        if (view[rotate[r][2]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour) &&
                            !isTrailColour(view[rotate[r][6]].color) &&
                            view[rotate[r][0]].color != expectedNextPathColourToEdge)
                        {
                            return {cell:rotate[r][0], color:expectedNextPathColourToEdge};
                        }
                        break;

                    // C?N  ...
                    // ?C?  .N.
                    // ??P  ...

                    case 3:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][2]].color === expectedNextPathColourToEdge &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour))
                        {
                            return {cell:4, color:expectedNextPathColourToEdge};
                        }
                        break;

                    // C??  N..
                    // ?C?  ...
                    // ??P  ...

                    case 4:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour))
                        {
                            return {cell:rotate[r][0], color:expectedNextPathColourToEdge};
                        }
                        break;

                    /////// MOVING ///////

                    // C?P  ...
                    // ?C?  ...
                    // ??C  N..
                    case 5:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][2]],currentCellColour) &&
                            view[rotate[r][6]].color != expectedNextPathColourToEdge)
                        {

                            if (view[rotate[r][6]].ant === null)
                            {
                                return {cell:rotate[r][6], color:expectedNextPathColourToEdge};
                            }
                            else
                            {
                                return NO_OP;
                            }
                        }
                        break;

                    // C?P  ...
                    // ?C?  ...
                    // N?C  M..
                    case 6:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][2]],currentCellColour) &&
                            view[rotate[r][6]].color === expectedNextPathColourToEdge)
                        {
                            cellToMoveTo = rotate[r][6];
                        }
                        break;

                    // Special case. we need to first paint the cell prior to moving other wise will cause corruption
                    // C??  ...
                    // ?C?  ...
                    // C??  ..N
                    case 7:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            view[rotate[r][8]].color != expectedNextPathColourToEdge)
                        {
                            if (view[rotate[r][8]].ant === null)
                            {
                                return {cell:rotate[r][8], color:expectedNextPathColourToEdge};
                            }
                            else
                            {
                                return NO_OP;
                            }
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // C?N  ..M
                    case 8:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            view[rotate[r][8]].color === expectedNextPathColourToEdge)
                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    // C??  ..M
                    // ?C?  ...
                    // P?C  ...
                    case 9:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][6]],currentCellColour))
                        {
                            cellToMoveTo = rotate[r][2];
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // P??  ..M
                    case 10:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][6]],currentCellColour))
                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // ???  M..
                    case 11:
                        if (view[rotate[r][0]].color === currentCellColour)

                        {
                            cellToMoveTo = rotate[r][6];
                        }
                        break;
                    // ???  ...
                    // ?C?  ...
                    // P??  ?.M
                    case 12:
                        if (isCellTrailToQueen(view[rotate[r][6]],currentCellColour))

                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    }
                    if (cellToMoveTo>-1)
                    {
                        return {cell:view[cellToMoveTo].ant === null?cellToMoveTo:4};
                    }
                }
            }
            return NO_OP;
        }

        // worker is transporting food
        else
        {
            // worker deadlock avoidance
            for (i=0; i<9; i+=2)
            {
                // does the cell have another ant in it?
                if (i!=4 && view[i].ant!=null && !(view[i].ant.type===ANT_TYPE_QUEEN && view[i].ant.friend))
                {
                    // attempt to pick an empty random trail-cell
                    for (i = randomInt(view,54321)%9;i>0;i--)
                    {
                        if (view[i].ant===null && view[i].food===0 && isTrailColour(view[i].color))
                        {
                            return {cell:i};
                        }
                    }

                    // no luck... just pick a random empty cell
                    for (i = randomInt(view,12345)%9;i>0;i--)
                    {
                        if (view[i].ant===null && view[i].food===0)
                        {
                            return {cell:i};
                        }
                    }

                    // deadlock unavoidable!
                    return NO_OP;
                }
            }

//            // this is to try and unstick stuck ants
//            if (randomInt(view,1)%20==1)
//            {
//                // attempt to pick an empty random trail-cell
//                for (i = randomInt(view,666)%9;i>0;i--)
//                {
//                    if (view[i].ant==null && view[i].food==0 && isTrailColour(view[i].color))
//                    {
//                        return new Move(i);
//                    }
//                }
//            }


            // decide move action
            for (var priority = 0; priority <14;priority++)
            {
                // repeat for each rotation
                var indecies = shuffleIndecies(view,random,4);
                for (var j=0;j<4;j++)
                {
                    var r = indecies[j];
                    var cellToMoveTo =-1;

                    switch(priority)
                    {
                        // PRE-EMPTIVE PATH PRUNING

                    // C?X  X..
                    // ?X?  ...
                    // P?X  ...
                    case 0:
                        if (isTrailColour(view[rotate[r][0]].color) &&
                            !isTrailColour(view[rotate[r][2]].color) &&
                            !isTrailColour(view[rotate[r][4]].color) && 
                            prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][5]].color)
                        {
                            return {cell:rotate[r][0], color: 1};
                        }
                        break;


                        // ?C?  ...
                        // CXN  X..
                        // ?X?  ...
                        case 1:
                            if (!isTrailColour(view[rotate[r][4]].color) &&
                                !isTrailColour(view[rotate[r][7]].color) &&
                                isTrailColour(view[rotate[r][1]].color) && 
                                view[rotate[r][3]].color === view[rotate[r][1]].color &&
                                nextTrailColor(view[rotate[r][1]].color) === view[rotate[r][5]].color)
                            {
                                return {cell:rotate[r][3], color: 1};
                            }
                            break;

                        // ?C?  ...
                        // PXC  ..X
                        // ?X?  ...
                        case 2:
                            if (!isTrailColour(view[rotate[r][4]].color) &&
                                !isTrailColour(view[rotate[r][7]].color) &&
                                isTrailColour(view[rotate[r][1]].color) && 
                                view[rotate[r][5]].color === view[rotate[r][1]].color &&
                                prevTrailColor(view[rotate[r][1]].color) === view[rotate[r][3]].color)
                            {
                                return {cell:rotate[r][5], color: 1};
                            }
                            break;

                        // N??  ..N
                        // ?C?  ...
                        // C?C  ...

                        case 3:
                            if (isTrailColour(view[rotate[r][4]].color) &&
                                view[rotate[r][2]].color != expectedNextPathColourToEdge &&
                                view[rotate[r][8]].color === currentCellColour &&
                                view[rotate[r][0]].color === expectedNextPathColourToEdge &&
                                view[rotate[r][6]].color === currentCellColour)
                            {
                                return {cell:rotate[r][2], color:expectedNextPathColourToEdge};
                            }
                            break;

                        // N??  ...
                        // ?X?  .C.
                        // C?C  ...


                        case 4:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][8]].color) &&
                                view[rotate[r][0]].color === nextTrailColor(view[rotate[r][8]].color) &&
                                view[rotate[r][8]].color === view[rotate[r][6]].color)
                            {
                                return {cell:rotate[r][4], color:view[rotate[r][8]].color};
                            }
                            break;

                        // N??  ..C
                        // ?C?  ...
                        // C?P  ...

                        case 5:
                            if (isTrailColour(view[rotate[r][4]].color) && 
                                view[rotate[r][0]].color === expectedNextPathColourToEdge &&
                                view[rotate[r][6]].color === currentCellColour &&
                                isCellTrailToQueen(view[rotate[r][8]],currentCellColour) &&
                                view[rotate[r][2]].color != currentCellColour)
                            {
                                return {cell:rotate[r][2], color:currentCellColour};
                            }
                            break;

                        // C?N  ...
                        // ?X?  .N.
                        // ??P  ...

                        case 6:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][0]].color) && 
                                view[rotate[r][2]].color === nextTrailColor(view[rotate[r][0]].color) &&
                                view[rotate[r][8]].color === prevTrailColor(view[rotate[r][0]].color))
                            {
                                return {cell:rotate[r][4], color:nextTrailColor(view[rotate[r][0]].color)};
                            }
                            break;

                        // ??P  ...
                        // ?X?  .N.
                        // ??N  ...

                        case 7:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][2]].color) &&
                                nextTrailColor(view[rotate[r][2]].color) === view[rotate[r][8]].color)
                            {
                                return {cell:4, color:view[rotate[r][8]].color};
                            }
                            break;



                        // if we are on the corner of a trail band... move opposite to the apex
                        case 8:
                            if (isTrailColour(currentCellColour) &&
                                view[rotate[r][0]].color === currentCellColour &&
                                view[rotate[r][2]].color === currentCellColour)
                            {
                                if (randomInt(view,currentCellColour)%2 === 0)
                                {
                                    cellToMoveTo = rotate[r][0];
                                }
                                else
                                {
                                    cellToMoveTo = rotate[r][2];
                                }
                            }
                            break;

                        // if we on the opposite corner of a trail band... move back toward the apex
                        case 9:
                            if (isTrailColour(currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][0]],currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][2]],currentCellColour))
                            {
                                if (randomInt(view,currentCellColour)%2 === 0)
                                {
                                    cellToMoveTo = rotate[r][0];
                                }
                                else
                                {
                                    cellToMoveTo = rotate[r][2];
                                }
                            }
                            break;
                        // if an adjacent cell is a trail to the queen, move that way
                        case 10:
                            if (isTrailColour(currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][0]],currentCellColour))
                            {
                                cellToMoveTo = rotate[r][0];
                            }
                            break;
                        // if we are not on a trail and an adjacent cell is a trail, then move that way
                        case 11:
                            if (!isTrailColour(currentCellColour) && isTrailColour(view[rotate[r][8]].color))
                            {
                                cellToMoveTo = rotate[r][8];
                            }
                            break;
                        // are we on a cell between trail cells? if so then move onto a cell on the trail.
                        case 12:
                            if (isTrailColour(view[rotate[r][1]].color))
                            {
                                cellToMoveTo = rotate[r][1];
                            }
                            break;
                        // are we on a terminal trail cell? if so then move onto a cell on the trail.
                        case 13:
                            if (isTrailColour(view[rotate[r][0]].color))
                            {
                                cellToMoveTo = rotate[r][0];
                            }
                            break;

                    }
                    if (cellToMoveTo>-1)
                    {
                        if (view[cellToMoveTo].ant != null || view[cellToMoveTo].food > 0) continue;
                        return {cell:cellToMoveTo};
                    }
                }
            }
            return NO_OP;
        }

    }

    return getAction(view);

버전 1

version1

이 항목의 기본 전제는 확대되는 사각형 나선을 검색하는 것입니다. 검색 광장 주변 확장은 빠른 음식 배달과 주변으로 돌아갈 수 있도록 3 밴드 반복 패턴을 만듭니다.

항목의 이름은 고전적인 퍼즐 게임 BolderDash의 "반딧불"적의 이름이며, 반복되는 세 가지 색상 패턴은 적을 연상시킵니다.

이 초기 버전은 잠재적 인 버그가있는 동안 기본 항목이되기위한 기본 요구 사항을 충족합니다. 개미는 음식을 수집하여 여왕에게 반환합니다. 그러나 음식은 즉시 노동자로 전환되므로 토너먼트에 참가하지 마십시오.

그러나 다음 버전에서는 기본적으로 방법을 변경하고 개미 이동 / 페인트 순서를 바꿀 것입니다. 페인트에서 이동, 페인트로 이동합니다. 확실하지는 않지만, 개미가 인접한 개미에 의해 다시 칠해져있는 세포에서 일부 세포 색 패턴 손상이 발생한다고 생각합니다. 순서를 변경하면 위험을 줄이는 데 도움이되지만 그림을 그리기 전에 이동하는 것이 더 복잡하거나 위험 할 수 있습니다.

버전 2

버전 2

이 버전은 우수하며 이제 45도 회전하여 작업자 개미 단계 당 더 많은 탐사를 할 수 있습니다.

또한 음식을 수집합니다 (주의가 산만하지 않은 경우)

그러나 그것은 강력하지 않으며 다른 개미의 흔적에 의해 쉽게 중단됩니다. 따라서 현재로서는 좋은 경쟁자가 아닙니다.

그러나 혼자 남겨두면 평균 300 명의 직원이 수집 한 700 개의 식품입니다.

버전 2.1

여왕이 음식을 먹지 않을 때 일꾼을 만들지 않도록 위생 검사를 추가했습니다.

버전 2.1.1

2.1에서 수정 사항을 수정했습니다 (실제로 개미보기의 "음식"필드를 사용하지 않았으므로 null 객체를 참조했습니다.

버전 2.1.1.1

/ me 손에 머리를 숨 깁니다

스폰 기능에서 간단한 인덱싱 버그를 발견했습니다. 이는 여왕이 자신의 위에 스폰하려고 시도 할 수 있음을 의미합니다. 이제 수정되었습니다.

버전 2.2

불법 스폰 버그를 다시 도입 한 복사 붙여 넣기 오류 수정

버전 2.2.1

여왕이 첫 번째 음식을 찾으려고 시도 할 때 시작 스크램블에서 불법으로 움직일 수있는 문제를 수정했습니다.


당신의 전략은 Zigurrat와 같은 약점 : 도난으로 고통 받고 있습니다. 약 90 초 안에 Firefly를 대상으로 뱀파이어에서 Zigurrat 식별 코드를 조정할 수있었습니다. 문자 그대로 "60 줄의 코드 복사, 60 줄의 코드 붙여 넣기, 3 개의 숫자 변경"입니다. 그러나 대신 Zigurrat-ID 코드를 모듈 식으로 만드는 것을 선호합니다 ( "이러한 색상으로").
Draco18s

귀하의 개미도 많이 쌓아 하나의 그림이 하나가 뒤에 올 것이다 경우 대기 트리거의 오른쪽 조합이 대기 - 어이 튀어과 새 줄을 시작하게 될 때까지. 앞에 친절한 개미가 있다는 것을 감지하고 새로운 라인을 시작하기 위해 터지는 것이 쉽습니다. 모퉁이가 기다릴 필요조차 없습니다. 두 번째 문제는 별도의 선에있는 두 개의 개미가 같은 그리기 단계에있을 때입니다. 바깥쪽에있는 모서리가 모서리를 그리고 안쪽에있는 모서리가 다시 그립니다. 이 상황에서도 이웃 개미를 감지 할 수 있어야합니다 (가장 좋은 행동은 다른 개미가 움직일 때까지 기다리는 것입니다).
Draco18s

@ Draco18s 네,이 초기 버전에는 몇 가지 결함이 있습니다 :-) 그러나 시작하는 곳입니다. 도둑질 위협과 관련하여 : 나는 적 도둑질 여왕을 찾고 "도둑질"수비 개미를 만들 계획입니다. 손실을 최소화해야합니다.
Moogie

오, 나는 그것이 단지 관찰하기 시작하는 곳이라는 것을 알고 있습니다. :)
Draco18s

1
끝났어? 뱀파이어 박쥐로 들어가서 장소를 부술 수 있습니까? : D
Draco18s

4

만델 브란트

모든 답변에는 Formic Functions Framework 형식의 유사한 저수준 논리가 포함되어 있습니다.

"높은 수준의 논리가 여기에서 시작됨"은 프레임 워크 코드의 끝을 나타냅니다.

경고 : 이 항목은 주로 Formic Functions 규칙 세트에서 가능한 기능에 대한 데모입니다. 비어 있지 않은 맵에서 철저하게 테스트되지 않았습니다. 두 번의 경기에서 살아남 았지만 오랫동안 자격을 유지할 것으로 기대하지는 않습니다.

// FORMIC FRAMEWORK \\
//  Version 7.0.4   \\
const QUEEN = 5;
const HERE = view[4];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const ROTATIONS = [
    [0, 1, 2,
     3, 4, 5,
     6, 7, 8],

    [6, 3, 0,
     7, 4, 1,
     8, 5, 2],

    [8, 7, 6,
     5, 4, 3,
     2, 1, 0],

    [2, 5, 8,
     1, 4, 7,
     0, 3, 6]
];
const NEIGHBORS = [
    [1, 4, 3],
    [2, 5, 4, 3, 0],
    [5, 4, 1],
    [0, 1, 4, 7, 6],
    [0, 1, 2, 5, 8, 7, 6, 3],
    [8, 7, 4, 1, 2],
    [3, 4, 7],
    [6, 3, 4, 5, 8],
    [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = false;
const log = DEBUG_MODE ? console.log : () => { };

function cells(...indices) {
    return indices.map(i => view[i]);
}
function colors(...indices) {
    return cells(...indices).map(c => c.color);
}
function ants(...indices) {
    return cells(...indices).map(c => c.ant);
}

function isColor(color, index) {
    return view[index].color === color;
}
function isAnyColor(colors, index) {
    return colors.includes(view[index].color);
}
function hasFood(index) {
    return view[index].food === 1;
}
function hasAnt(qualifies, index) {
    const a = view[index].ant;
    return a && (!(qualifies instanceof Function) || qualifies(a));
}
function hasFriend(type, index) {
    return hasAnt(a => a.friend && (!type || a.type === type), index);
}
const hasAnyFriend = bind(hasFriend, null);
function bind(f, ...args) {
    return f.bind(null, ...args);
}

function noTransform() {
    return { revert() { }, detransformAction() { } };
}
function indexTransform(indices) {
    const revertedIndices = new Array(9);
    for (let i = 0; i < 9; ++i) {
        revertedIndices[indices[i]] = i;
    }

    view = indices.map(index => view[index]);

    return { revert() { view = revertedIndices.map(index => view[index]); }, detransformAction(action) { action.cell = indices[action.cell]; } };
}

const rotationTransformers = [noTransform, ...ROTATIONS.slice(1).map(r => bind(indexTransform, r))];

function bestTransformers(transformers, scorer) {
    let bestScore = 0;
    const bestIndices = [];
    const bestTransformers = [];
    for (let i = 0; i < transformers.length; ++i) {
        const t = transformers[i];
        const {revert} = t();
        const score = scorer();
        revert();
        if (score > bestScore) {
            bestScore = score;
            bestIndices.length = 0;
            bestTransformers.length = 0;
        }
        if (score >= bestScore) {
            bestIndices.push(i);
            bestTransformers.push(t);
        }
    }

    return {score: bestScore, indices: bestIndices, transformers: bestTransformers};
}
function* withBestTransformation(transformers, scorer, continuation) {
    const best = bestTransformers(transformers, scorer);
    if (best.score > 0) {
        const {revert, detransformAction} = best.transformers[0]();
        for (const output of continuation(best)) {
            if (isAction(output)) {
                detransformAction(output);
            }
            yield output;
        }
        revert();
    }
}
const withBestRotation = bind(withBestTransformation, rotationTransformers);

const wait = {cell: 4};
function move(index) {
    return index >= 0 && index < 9 && view[index].ant === null && (view[index].food === 0 || ME.food === 0 || ME.type === QUEEN) ? { cell: index } : null;
}
function moveMany(...indices) {
    return indices.map(move);
}
function paint(color, index) {
    return index >= 0 && index < 9 && color >= 1 && color <= 8 && view[index].color !== color ? { cell: index, color } : null;
}
function paintMany(colors, ...indices) {
    return pairMap(indices, colors, paint);
}
function spawn(type, index) {
    return index >= 0 && index < 9 && view[index].ant === null && view[index].food === 0 && ME.food > 0 && ME.type === QUEEN && type >= 1 && type <= 4 ? { cell: index, type } : null;
}
function spawnMany(types, ...indices) {
    return pairMap(indices, types, spawn);
}
function pairMap(mainArr, sideArr, func) {
    return mainArr.map((v, i) => func(sideArr[i % sideArr.length], v));
}

function isAction(value) {
    return value instanceof Object && value.cell !== undefined; // TODO: Make this more strict.
}

log('=== start logic ===');
for (const output of main()) {
    if (isAction(output)) {
        log('=== end logic ===');
        return output;
    }
}

throw 'Decision was omitted.';

function* main() {
    // HIGH-LEVEL LOGIC STARTS HERE \\

    // TARGET SIZE:  2^21 pixels -- SUPPORTED
    // STRETCH GOAL: 2497 x 996
    // MAX POSSIBLE: 2500 x 1000

    // How long the painting triplet will go on for until they begin returning to the shifting station.
    // This value should not exceed 997 for the painter to work in all cases, or 2497 if you don't care about being positioned vertically.
    // It also shouldn't be too low. The exact lowest value is unclear, but it's likely to be in the teens.
    const LENGTH = 6 * 11;

    // Which function will be used for painting in the pixels.
    const getPictureColorAt = mandelbrot;

    function notReallyRainbow(index) {
        return index % 6 + 2;
    }
    function fromColorString(index) {
        // Input your own color string ({ a, b, c, d, e, f, g, h } => { 8, 7, 6, 4, 5, 3, 2, 1 }).
        const colorString = '';

        return [8, 7, 6, 4, 5, 3, 2, 1][colorString.charCodeAt(index % colorString.length) - 'a'.charCodeAt(0)];
    }
    function mandelbrot(index) {
        const ESCAPE = 2 ** 2, MAX_I = 8 * 10 - 1;
        const x0 = (index % LENGTH) / (LENGTH - 1) * 3 - 2, y0 = Math.floor(index / LENGTH) / (Math.floor(LENGTH * 2 / 3) - 1) * 2 - 1;
        let x = 0, y = 0;
        for (let i = 0; i < MAX_I; ++i) {
            [x, y] = [x * x - y * y + x0, 2 * x * y + y0];
            if (x * x + y * y > ESCAPE) {
                return (i + 1) % 8 + 1;
            }
        }
        return 8;
    }

    // WARNING! Beyond likely lies awful code.
    // There are no more tunable parameters.
    // Continue reading at your own risk.

    const L1_OVERFLOW = 4096;
    const FILL_ORDER_INDEX = [1, 2, 3, 6];
    const FILL_ORDER_DIGIT = [0, 1, 2, 4];

    function parseNumber(...indices) {
        return indices.reduceRight((a, index) => (a << 3) + (index !== -1 ? view[index].color - 1 : 0), 0);
    }

    function colorAtDigit(n, d) {
        return ((n >>> (d * 3)) & 7) + 1;
    }

    function paintPictureFragment(number) {
        log(`initialized painter with ${number}`);
        return paint(getPictureColorAt(number), 0);
    }

    const COPIER = 1;
    const COUNTER = 2;
    const MAJOR = 3;
    const MINOR = 4;

    function* moveWait(index) {
        yield move(index);
        yield wait;
    }

    log(`type: ${ME.type}`);
    switch (ME.type) {
        case COPIER: {
            yield* withBestRotation(() => Math.max(hasFriend(QUEEN, 7) + hasFriend(MINOR, 3), hasFriend(QUEEN, 6) + hasFriend(MINOR, 0)) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, COUNTER, 7), function*() {
                if ([6, 3].findIndex(hasAnyFriend) === -1) {
                    yield paint(8, 3);
                    yield move(3);
                }
                yield wait;
            });
            yield* withBestRotation(bind(hasFriend, COUNTER, 8), function*() {
                const targetIndex = FILL_ORDER_INDEX[view[4].color - 3];
                yield paint(view[5].color, targetIndex);
                yield wait;
            });
            yield wait;
        }

        case COUNTER: {
            yield* withBestRotation(() => hasFriend(COPIER, 2) + hasFriend(MAJOR, 0) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, COPIER, 1), function*() {
                if (hasFriend(MAJOR, 0)) {
                    yield paint(view[6].color, 8);
                }
                yield wait;
            });
            yield* withBestRotation(bind(hasFriend, COPIER, 0), function*() {
                if (!hasAnyFriend(6)) {
                    const progress = view[0].color;
                    if (progress === 8) {
                        const number = parseNumber(8, 7, 4, 1) + 1;
                        yield* paintMany([1, 2, 3].map(bind(colorAtDigit, number)), 3, 5, 2);
                        yield paint(7, 0);
                    } else if (progress === 7) {
                        const number = parseNumber(8) + 1;
                        yield paint(colorAtDigit(number, 0), 4);
                        yield paint(6, 0);
                    } else {
                        const number = parseNumber(...progress === 6 ? [4, 3] : [7, 8], 5, 2) * LENGTH;
                        if (progress > 2) {
                            if (progress === 6) {
                                yield* paintMany(colors(4, 3), 7, 8);
                            } else if (progress === 5) {
                                yield* paintMany([5, 6].map(bind(colorAtDigit, number)), 3, 4);
                            }
                            yield paint(colorAtDigit(number, FILL_ORDER_DIGIT[progress - 3]), 1);
                            if (progress !== 3) {
                                yield paint(progress - 1, 0);
                            } else {
                                yield paint(number + 1 === L1_OVERFLOW ? 2 : 1, 0);
                            }
                        } else {
                            yield paint(colorAtDigit(number, 3), 1);
                            yield wait;
                        }
                    }
                }
            });
            yield wait;
        }

        case MAJOR: {
            yield* withBestRotation(bind(hasFriend, COPIER, 5), bind(moveWait, 6));
            yield* withBestRotation(() => hasFriend(QUEEN, 7) + hasFriend(MINOR, 1) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, QUEEN, 2), bind(moveWait, 1));
            yield* withBestRotation(bind(hasFriend, MINOR, 2), function*() {
                const number = parseNumber(-1, -1, -1, -1, 3, 4, 5) + (isColor(2, 1) ? L1_OVERFLOW : 0);
                yield* paintMany([4, 5, 6].map(bind(colorAtDigit, number)), 6, 7, 8);
                yield move(7);
            });
            yield wait;
        }

        case MINOR: {
            yield* withBestRotation(() => hasFriend(COPIER, 8) + hasFriend(QUEEN, 6) - hasFriend(MAJOR, 3) - 1, bind(moveWait, 7));
            yield* withBestRotation(() => hasFriend(MAJOR, 6) + hasFriend(QUEEN, 7) - 1, bind(moveWait, 3));
            yield* withBestRotation(() => hasFriend(MAJOR, 8) - hasFriend(QUEEN, 7), bind(moveWait, 5));
            yield* withBestRotation(() => hasFriend(MAJOR, 7) + hasFriend(QUEEN, 5) - 1, bind(moveWait, 1));
            yield* withBestRotation(bind(hasFriend, QUEEN, 6), function*() {
                if (hasFriend(MAJOR, 3)) {
                    yield wait;
                }
                const number = parseNumber(0, 1) + 1;
                yield* paintMany([0, 1].map(bind(colorAtDigit, number)), 3, 4);
                yield move(7);
            });
            yield wait;
        }

        case QUEEN: {
            if (DIRECTIONS.some(hasAnyFriend)) {
                yield* withBestRotation(bind(hasFriend, COPIER, 5), function*() {
                    if (!hasFriend(COUNTER, 7)) {
                        yield spawn(COUNTER, 8);
                    }
                    if (!hasFriend(MAJOR, 3) && !hasFriend(MAJOR, 0)) {
                        yield spawn(MAJOR, 6);
                    }
                    yield spawn(MINOR, 0);
                    if (!hasFriend(MAJOR, 0) && hasFriend(MAJOR, 3)) {
                        yield move(7);
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MAJOR, 2), function*() {
                    if (!hasFriend(MINOR, 8)) {
                        yield move(1);
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MINOR, 0), function*() {
                    if (hasFriend(MAJOR, 3)) {
                        yield move(1);
                        yield wait;
                    } else if (hasFriend(MAJOR, 6)) {
                        yield wait;
                    }
                });

                yield* withBestRotation(bind(hasFriend, MAJOR, 7), function*() {
                    if (!hasFriend(COPIER, 6)) {
                        yield paintPictureFragment(parseNumber(1, 2, 3, 5, 6, 7, 8));
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MINOR, 5), function*() {
                    if (isColor(3, 4)) {
                        const number = parseNumber(1, 2, 3, 5) + 1;
                        yield* paintMany([colorAtDigit(number, 2), number + 1 === L1_OVERFLOW ? 2 : 1, colorAtDigit(number, 3)], 6, 7, 8);
                        yield move(7);
                        yield wait;
                    } else {
                        const number = parseNumber(1, 2, 3, 5, 6, 7, 8);
                        yield paintPictureFragment(number);
                        if ((number + 1) % LENGTH === 0) {
                            yield move(8);
                            yield wait;
                        }
                        yield paint(3, 4);
                    }

                    throw 'illogical failure 1';
                });

                throw 'illogical failure 2';
            }

            yield* moveMany(...DIAGONALS_ORTHOGONALS.filter(hasFood));

            if (ME.food >= 4) {
                yield* spawnMany([COPIER], ...ORTHOGONALS);
            }

            yield* moveMany(...DIAGONALS_ORTHOGONALS.filter(bind(isColor, 1)), ...DIAGONALS_ORTHOGONALS); // TODO: Watch out for accidental entrapment.
            yield wait;
        }
    }
}

갤러리

만델 브로트 작은 만델 브로트


설명

나는 설명을 아주 짧게 할 것이지만, 내가 들어 가지 않을 것으로 생각하면서 불쾌한 세부 사항이 많이 있다는 것을 명심하십시오.

1 단계

첫째, 여왕은 4 명의 음식을 모아 4 명의 노동자를 만들고 각기 다른 목적을 수행합니다. 그녀는 그림을 망칠 가능성을 최소화하기 위해 색을 남기지 않습니다. 왜 그런지 알게 될 것입니다.

2 단계

4 명의 작업자를 스폰 한 후, 엔트리의 핵심 루프가 즉시 시작됩니다. 이제부터는 항목이 그렇게하기 때문에 일관된 뷰 방향을 가정합니다.

먼저 그림을위한 올바른 방향을 얻기 위해 조정 된 5-ant 댄스가 수행됩니다. 이것은 가장 변동성이 큰 단계 일 수 있으며 여기에서 적의 개입으로 인해 참가 자격이 박탈 될 수 있습니다. 그 후 개미가 헤어졌다.

3 마리의 개미 (여왕과 2 명의 노동자)가 그림을 그립니다. 21 비트 (셀당 7 비트 * 셀당 3 비트)의 정수를 색상 형태로 전달하므로 원하는 이미지로 색인 할 수 있습니다. 기본적으로이 이미지는 Mandelbrot 세트입니다. 또한 왼쪽 위 셀은 페인트중인 픽셀을 위해 예약되며 중앙 셀은이 설명의 범위를 벗어난 것들을 위해 예약됩니다. 삼중 항은 서로를 찾아 방향을 알아 내기 때문에 색상을 안내하기 위해 색상이 필요하지 않습니다. 매 사이클마다 정수를 1 셀씩 아래로 이동하여 그렇게 할 때마다 1 씩 증가시킵니다. 그려진 선의 끝에 도달하면 루프가 종료됩니다.LENGTH일정한. 이 시점에서 3 인의 조율 된 춤이 시작되고 트리오는 끝나는 어색한 구성으로 이어집니다. 여왕은 또한 춤을 추는 동안 오른쪽으로 이동합니다. 그들은 그들을 기다리는 한 쌍의 개미와 만날 때까지 위쪽으로 여행합니다.

여왕과 도우미가 돌아 오기를 기다리는 동안 개미 한 쌍은 화가가 도착한 후에도 계속 일할 수 있도록 현지 색 환경을 설정합니다. 이것은 파악하기 가장 어려운 부분이었습니다. 한 개미는 4 색 (12 비트) 정수를 유지하며 다른 개미에게 명령을 제공하는 데 사용됩니다. 이 지시 사항은 어떤 셀에 어떤 셀을 그려야하는지 그리고 어떤 색으로 칠해야하는지 설명합니다. 이것은 단일 개미가 채색 자체를 수행하는 데 필요한 모든 정보를 저장하기에 충분한 공간이 없기 때문에 필요합니다. 이 프로세스 전과 도중에 정수 유지 보수자가 숫자 1을 오른쪽으로 이동하고 1을 증가시켜야합니다. 명령 릴레이가 완료되면 정수 유지 보수자는 액세스 할 수있는 셀을 채우고 완료합니다. 환경 설정. 최대 절전 모드가 시작됩니다.

세 개미가 짝으로 돌아와서 5 개미 춤을 다시 시작하면 사이클이 완료됩니다.


이 항목에는 매개 변수가 있습니다. 현재 작은 만델 브로트 세트를 그리도록 조정되었습니다. 당신은 조정할 수 있습니다LENGTH 그림의 그림을 하거나 그림 그림 기능을 교체하거나 자신의 롤을 할 수 있습니다. 즐기세요!

권장 컨트롤러 : dzaima 년대 .


변경 로그

버전 1.0

  • 초판

와. 나는이 도전이 정보를 제한하고 정보가 부족하도록 특별히 설계했으며, 개미 간의 협력으로이 문제를 해결할 수있는 것에 여전히 놀랐습니다.
trichoplax

나는 이것이 경쟁적인 입장이 아니라 개념의 증거라는 것에 감사하지만, 다른 여왕들이 음식을 도난 당할 수 있도록 적절한 패턴으로 여왕의 함정으로 실용적으로 적용 할 수 있는지 궁금합니다.
trichoplax

1
다른 모든 플레이어에 대해 어떻게 작동하는지 확인하기 위해 몇 가지 게임을 실행 한 결과 개념 증명으로도 점수가 가장 낮지 않다는 점을 지적하는 것이 좋습니다. 여러 플레이어보다 우수합니다. 전체 토너먼트가 실행되면이 토너먼트는 마지막이 아닙니다.
trichoplax

1
왜? 왜? 왜 이렇게 하시겠습니까? 크리 키,이 도전은 내가 세 가지 다른 직업
Draco18s

1
@ Draco18s 나는이 도전을 너무 좋아합니다 : P
Alion

3

고독한 늑대

모든 대답은 동일한 하위 수준 도우미 기능 집합을 공유합니다. 이 답변과 관련된 코드를 보려면 "고수준 논리가 여기서 시작됩니다"를 검색하십시오.

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var COLOURS = random_colour_band(colours_excluding([1]));
return play_safe([
  grab_nearby_food,
  fast_diagonal.bind(null, COLOURS),
  go_anywhere,
  {cell: 1, color: COLOURS.next()}
]);

그래서 몇 가지 제 대답에서 음식을 빨리 모으기 위해 동일한 초기 단계를 사용했습니다. 개미가 게임 전체에 해당 전략을 사용하면 어떻게됩니까? 글쎄 그들은 그들이 잘하는 것으로 밝혀졌습니다.

이것은 주변의 음식을 움켜 쥐고 빛의 절반 속도로 들판을 가로 질러 경주합니다. 음식을 잡을 때 방향이 무작위로 바뀔 가능성이 있으며 이미 자신이나 다른 곳으로 덮여있는 지역을 피하려고 시도합니다. 작업자 개미가 생성되지 않습니다.

이론적으로 이것은 프레임 당 2.5 셀을 다루며 끔찍한 것은 아니며 어떤 식 으로든 잡거나 엉망으로 만드는 것은 거의 불가능합니다. 블랙홀을 제외한 모든 것보다 더 나은 것으로 보입니다 (블랙홀에 방해물이 생겼으므로 변경 될 수 있음).

나는이 도전에 대한 답변을 스팸으로 그만두겠다고 약속합니다…


최신 업데이트를 통해 더 많은 유형의 채워진 영역에서 멀어지면서 적용 대상을 다시 검색 할 가능성이 약간 줄어 듭니다.


그들은 모두 독특하고 흥미로운 전략 일 때 스팸이 아닙니다!
trichoplax

블랙홀의 방해 행위는 무엇입니까?
Draco18s

@ Draco18s는 어느 것이 확실하지 않지만 신속하게 대각선으로 파란색 선을 그려 블랙홀이 원하는 것보다 일찍 노동자를 낳지 못하게하고 너무 길어지게하여 모든 작업자가 어디서나 영원히 갈 수있게합니다. 화이트 페인트 미사일도 있습니다. 모두에게 화를 내며 블랙홀에 손을 대면 실제로 움직일 수 있습니다.
Dave

@ 데이브 봇은 Antdom Walking Artist
pppery

3

내뚫다

이 봇은 다른 봇 대부분을 제치고 90 개 가까이의 음식을 지속적으로 얻습니다.

var ORTHOGONALS = [1,3,5,7];
var CORNERS = [0,2,6,8];
var CENTER = 4;

var QUEEN = 5;

var no_op = {cell:CENTER};
var me = view[4].ant;

var ants;
var food;
var friendlies;
var unfriendlies;
var colors;

var j = 0;
var i = 0;
var cell = 0;
var rotation;

var out;

init_arrays();
var seed = rSeed();

var response;

var adjacents_all = {0:[1,3,4],1:[0,2,3,4,5],2:[1,4,5],3:[0,1,4,6,7],4:[0,1,2,3,4,5,6,7,8],5:[1,2,4,7,8],6:[3,4,7],7:[3,4,5,6,8],8:[4,5,7]};
var adjacents_ortho = {0:[1,3],1:[0,2,4],2:[1,5],3:[0,4,6],4:[1,3,5,7],5:[2,4,8],6:[3,7],7:[4,6,8],8:[5,7]};
var adjacents_diag = {0:[4],1:[3,5],2:[4],3:[1,7],4:[0,2,6,8],5:[1,7],6:[4],7:[3,5],8:[4]};

function valid_move(move) {
  if(!move || move.cell == undefined || move.cell < 0 || move.cell > 8) {return false;}
  if(move.type) {
    if(move.color) {return false;}
    if(move.type < 1 || move.type > 4) {return false;}
    if(view[move.cell].ant || view[move.cell].food) {return false;}
    if(me.type != QUEEN || me.food < 1) {return false;}
    return true;
  }
  if(move.color) {
    if(move.color < 1 || move.color > 8) {return false;}
    return true;
  }
  if(view[move.cell].ant){return false;}
  if(view[move.cell].food && me.food&& me.type != 5) {return false;}
  return true;
}

function steal_then_road(){
  if(count(unfriendlies, 5)>=1 && me.food==0){
    //steal from a queen with more than 30 food
    if(ants[unfriendlies.indexOf(5)].food>30){
      for(i=0;i<adjacents_ortho[unfriendlies.indexOf(5)].length;i++){
        if(ants[adjacents_ortho[unfriendlies.indexOf(5)][i]]==null){
          return {cell:adjacents_ortho[unfriendlies.indexOf(5)][i]};
        }
      }
    }
  }
  return road();
}

function try_corners(){
  for(i=0;i<4;i++){
    if(view[CORNERS[i]].ant==null){
      return {cell:CORNERS[i]};
    }
  }
}

function try_ortho(){
  for(i=0;i<4;i++){
    if(view[ORTHOGONALS[i]].ant==null){
      return {cell:ORTHOGONALS[i]};
    }
  }
}

function corner_then_ortho(){
  if(try_corners()){return try_corners();}
  if(try_ortho()){return try_ortho();}
  return {cell:4}; //PANIC!
}

function ortho_then_corner(){
  if(try_ortho()){return try_ortho();}
  if(try_corners()){return try_corners();}
  return {cell:4}; //PANIC!
}

function road(color){
  if (colors[color] != color) {
      return {cell:CENTER,color:color};
    }
  for (i = 0; i < 9; i++) {
    if (colors[i] == color && ants[8 - i] == null && i != color) {
      return {cell:8-i};
    }
  }
}

function color_self(color){
  return {cell:4,color:color};
}

function make_valid_move(move){
  if(valid_move(move)){return move;}
  return no_op;
  //return{cell:seed%9,color:seed%7+1};
}

function count(array, element) {
  out = 0;
  for (j = 0; j < array.length; j++) {
    if (array[j] == element) {
      out++;
    }
  }
  return out;
}

function target_ant(ant_type, location) {
  for (i = 0; i < 4; i++) {
    if (ants[location] != null) {
      if (ants[location].type == ant_type) {
        return i;
      }
    }
    ants = rot_left(ants);
    friendlies = rot_left(friendlies);
    unfriendlies = rot_left(unfriendlies);
    food = rot_left(food);
    colors = rot_left(colors);
  }
}


function target_color(color, location) {
  for (i = 0; i < 4; i++) {
    if (colors[location] != null) {
      if (colors[location].type == color) {
        return i;
      }
    }
    ants = rot_left(ants);
    friendlies = rot_left(friendlies);
    unfriendlies = rot_left(unfriendlies);
    food = rot_left(food);
    colors = rot_left(colors);
  }
}

function init_arrays() {
    ants = new Array(9);
  for (cell = 0; cell < 9; cell++) {ants[cell] = view[cell].ant;}


  food = new Array(9);
  for (cell = 0; cell < 9; cell++) {food[cell] = view[cell].food;}

  colors = new Array(9);
  for (cell = 0; cell < 9; cell++) {colors[cell] = view[cell].color;}

  friendlies = new Array(9);
  for (cell = 0; cell < 9; cell++) {
    if (ants[cell] != null) {
      if (ants[cell].friend) {friendlies[cell] = ants[cell].type;}
    }
  }

  unfriendlies = new Array(9);
  for (cell = 0; cell < 9; cell++) {
    if (ants[cell] != null) {
      if (!ants[cell].friend) {unfriendlies[cell] = ants[cell].type;}
    }
  }
}

function rot_n_pos(pos, n) {
  for (i = 0; i < n; i++) {
    pos = [2, 5, 8, 1, 4, 7, 0, 3, 6][pos];
  }
  return pos;
}

function rot_left(a) {
  return [a[2], a[5], a[8], a[1], a[4], a[7], a[0], a[3], a[6]];
} 

function rot_right(a) {
  return [a[6], a[3], a[0], a[7], a[4], a[1], a[8], a[5], a[2]];
}

function rSeed(){
  out=23;
  for(i=0;i<9;i++){
    if(food[i]){
      out+=17;
    }
    out += 3 * colors[i];
    if(ants[i]){
      out *= 19;
    }
  }
  return out;
}

function get_response(){
  if (me.type == 5) { //Queen Case:
    return type5();
  }
  else if (me.type == 1) {
    return type1();
  }
  else if (me.type == 2) {
    return type2();
  }
  else if (me.type == 3) {
    return type3();
  }
  else if(me.type == 4){
    return type4();
}

function type5(){
  if (me.food == 0 && count(friendlies, 1) == 0 && count(friendlies, 2) == 0) {
    if (count(food, 1) > 0) {
      for (j = 0; j < 9; j++) {
        if (food[j]) {
          return {cell: j};
        }
      }
    }
    // travel up
    // color own cell if not 4

    if(road()){return road();}

    //move
    for (i = 0; i < 9; i++) {
      if (ants[i] == null && i != 4) {
        return {cell:i};
      }
    }
    return corner_then_ortho();
  }
  if (me.food >= 1 && count(friendlies, 1) == 0 && count(friendlies, 2) == 0) {
    if (ants[5] == null) {
      return {cell:5,type:1};
    }
    if (ants[1] == null) {
      return {cell:5, type:1};
    }
    if (ants[3] == null) {
      return {cell:5,type:1};
    }
    if (ants[7] == null) {
      return {cell:5, type:1};
    }
    return color_self(5);
  }
  if (me.food == 0 && count(friendlies, 1) == 1 && count(friendlies, 2) == 0) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return ortho_then_corner();//PANIC!!! TODO: FIX
    }
    rotation = target_ant(1, 1);
    if (ants[0] == null) {
      return {cell: rot_n_pos(0, rotation)};
    } else {
      return corner_then_ortho;
    }
  }
  if (me.food >= 1 && count(friendlies, 1) == 1 && count(friendlies, 2) == 0) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return corner_then_ortho(); //PANIC!!! TODO: FIX
    }
    rotation = target_ant(1, 1);
    if (ants[3] == null) {
      return {cell: rot_n_pos(3, rotation),type: 2};
    }
    if (ants[0] == null) {
      return { cell: rot_n_pos(0, rotation)};
    }
    return {cell: 4};
  }
  if (count(friendlies, 1) == 1 && count(friendlies, 2) == 1) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(1, 1);
    if(food[0] || food[8]){
      return no_op;
    }
    if(ants[5]!=null){
      if(ants[5].type == 2 && ants[2]==null){
        return {cell: rot_n_pos(2, rotation)};
      }
    }
    return corner_then_ortho();
  }
  return corner_then_ortho();
}

function type1(){
//right flank
  if (count(friendlies, 5) == 0 && count(friendlies, 2) == 0 && count(friendlies,1) == 1) {
    //no friends = destruction
    return steal_then_road();
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 2) == 0 && count(friendlies,1) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(5, 3);
    if (ants[0] == null) {
      return {cell: rot_n_pos(0, rotation)};
    }
    return corner_then_ortho(); // PANIC!! TODO: FIX
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 2) == 1 && count(friendlies,1) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner(); 
    }
    rotation = target_ant(5, 3);
    if(friendlies[8] !=null){
      if(friendlies[8].type==2){
        if (ants[0] == null){
          return {cell: rot_n_pos(0, rotation)};
        }
      }
    }
    if (ants[0] != null) {
      if (ants[0].type == 2 && ants[6] == null) {
        return {cell: rot_n_pos(6, rotation)};
      }
    }
    if (ants[6] != null) {
      if (ants[6].type == 2 && ants[0] == null) {
        return {cell: rot_n_pos(0, rotation)};
      }
    }
    return corner_then_ortho();
  }
  return corner_then_ortho();
}

function type2(){
  //left flank
  if (count(friendlies, 5) == 0 && count(friendlies, 1) == 0  && count(friendlies,2) == 1) {
    return steal_then_road();
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 1) == 0  && count(friendlies,2) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(5, 1);
    if (ants[0] == null) {
      return {cell: rot_n_pos(2, rotation)};
    }
    return corner_then_ortho();
    }
    if (count(friendlies, 5) == 1 && count(friendlies, 2) == 1) {
      return {cell: 4,color:2};
    }
    }
  return corner_then_ortho();
}

function type3(){}
function type4(){}

response = get_response();

return make_valid_move(response);

전략.

1 단계 : 여왕 출격.

여왕은 Romanesco 도로와 유사한 기술을 사용하여 음식을 먹습니다 ( road()기능 사용). 그녀는 음식을 볼 때마다 2 단계를 활성화하여 1 형 노동자를 낳습니다.

2 단계 : 퀸 파트너 스크램블

여왕과 파트너는 방향을 맞추기 위해 서로를 사용하므로 빛의 속도로 움직입니다. 그들은 주변의 음식을 무시하고 그들에게 맞는 것을 얻습니다. 여왕이 음식을 얻었을 때, 그녀는 2 단계 노동자를 낳아 3 단계를 활성화시킵니다.

3 단계 : 피어싱.

세 개미는 서로를 사용하여 빛의 속도로 이동하면서 길을 찾습니다. 여왕은 노동자들 중 누구도 먹을 수없는 음식을 볼 때마다 그녀를 멈추고 노동자들이 그녀 주위를 회전하고 형성을 90도 돌립니다.

강점 :

3 개의 개미 형성은 흔적을 만들지 않고, 감싸지 않으며, 빛의 속도로 이동하여 이동 당 평균 0.1 % * 3 = 0.003의 음식을 얻습니다. 이는 평균적으로 게임당 평균 0.003 * 30000 = 90 음식에 해당하며 일반적으로 얻습니다.

약점 :

봇에는 두 가지 약점이 있습니다. 주요한 것은 개미 앞에서 걷는 개미입니다. 그 처리는 최고가 아니며 때로는 여왕이 과도한 양의 노동자를 만들게합니다. 운 좋게도 노동자들은 다른 여왕들 ( steal_then_road()) 을 훔치도록 계획되어있다 . 그러나 형성은 흔적을 만들지 않기 때문에 실제로 찾는 것은 불가능합니다.

또 다른 약점은 road()내가 고치고있는 문제가있는 것으로 보이는 알고리즘입니다. 브라운 운동 인 도로는 좋지 않습니다. 이것은 시작이 매우 느리고 건강하지 않은 상황에서 나쁜 탈출을 의미합니다.


이 개미는 실제로 내 강압 개미 와 동일 하지만 내 테스트에서 더 나쁜 것 같습니다. 내가 알아 차린 유일한 차이점은 여왕이 다른 노동자들이 도달 할 수없는 음식을 보았을 때 개미가 돌아가고, 제 2 형 노동자가 음식을 먹으면 내 차례가된다는 것입니다. 나는 당신의 개미도 잘 수행해야한다고 생각하지만, 때때로 그것이 저조한 이유를 이해할 수 없습니다.
K Zhang

@KZhang 재미있는. 필자의 테스트에서 피어스는 불필요하게 수십 개의 새로운 개미를 만들 때 개미 (Wildfire? Black Hole?)의 주요 간섭에 부딪 칠 때를 제외하고 일반적으로 더 잘 수행합니다. 시간과 테스트 만이 알려줄 것입니다.
fireflame2417

수정 후 다음 순위표를 위해 현재 토너먼트에 다시 포함되었습니다.
trichoplax

2
드문 상황 에서이 패턴이 무한 루프에 빠질 수 있음을 알았습니다. 구체적으로, 1 개의 공간으로 분리 된 2 개의 음식이 있다면, 여왕은 그들과 인접한 위치에 들어간다; 이런 일이 발생하면 패턴은 "돌지 않으면 놓칠 수있는 음식"에만 반응하고 "돌아 가면 놓칠 수있는 음식"에만 반응하지 않기 때문에 패턴이 계속 회전합니다.
Kamil Drakari

3

싱글 퀸

var C = 5;

for(var i = 0; i<9; i++)
{
  if(view[i].food === 1)
    return {cell:i};
}


if(view[4].color != 5 && !view[0].ant && !view[1].ant && !view[2].ant && !view[3].ant && !view[5].ant && !view[6].ant && !view[7].ant && !view[8].ant)
  return {cell:4, color:C};

if(!view[0].ant && 
   view[0].color != C && view[8].color === C && view[1].color != C && view[3].color != C && view[2].color != C && view[6].color != C)

      return {cell:0};

if(!view[2].ant && 
   view[2].color != C && view[6].color === C && view[1].color != C && view[5].color != C  && view[0].color != C && view[8].color != C)

     return {cell:2};

if(!view[6].ant && 
   view[6].color != C && view[2].color ===  C && view[3].color != C && view[7].color != C  && view[0].color != C && view[8].color != C)

     return {cell:6};

if(!view[8].ant && 
   view[8].color != C && view[0].color === C && view[5].color != C && view[7].color != C  && view[2].color != C && view[6].color != C)

     return {cell:8};


if(!view[0].ant)
  return {cell:0};

if(!view[2].ant)
  return {cell:2};

if(!view[6].ant)
  return {cell:6};

if(!view[8].ant)
  return {cell:8};


return {cell:4};

음식을 대각선으로 검색하는 간단한 코드. 오래된 지역을 검색하지 않으려 고 시도하지만 열린 공간을 찾기 위해 다른 지역을 검색하여 해당 지역을 통과하려고합니다.

고독한 늑대와 비슷한 전략으로 보입니다 (의도적이지 않음).


3

탐침

갱을 퍼트려 라!

익스플로러 (Explorer)는 음식을 여왕에게 다시 가져 오면서 최대한 멀리 퍼지는 것을 목표로하는 5 인 팀입니다.

여왕

여왕 자체는 3 단계 설정을 사용합니다.

스테이지 1.

경기가 시작될 때 좋은 여왕처럼 음식을 맛볼 수 있습니다. 그것은 음식을 찾을 때까지 대각선으로 직선으로 경로를 따라 간 다음 무작위로 방향을 바꿉니다. 음식이 4 개인 경우 2 단계로 이동합니다.

2 단계.

아마 8 번만 움직일 것입니다. 주변에있는 4 개의 타일을 4 개의 고유 한 색상으로 설정하고 각 유형에 따라 개미를 생성합니다. 모두 생성되면 3 단계로 이동합니다.

3 단계.

3 단계의 모든 경기는 남은 경기를 위해 여전히 앉아 있으며, 주변의 4 개의 타일이 올바르게 설정되어 있는지 확인합니다.

노동자

노동자 자체는 매우 간단한 2 단계 생물입니다. 첫째, 그들은 여왕이 2 단계를 마쳤다는 신호를 기다립니다. 두 번째 단계는 훨씬 더 복잡합니다 (그러나 여전히 단순합니다). 끝을 찾을 때까지 자체 경로를 따라 시계 방향으로 걷고 계속 확장합니다. 음식을 찾으면 음식에 손을 뻗은 다음 다시 경로를 따라 시계 방향으로 돌면서 여왕에게 다시 돌아옵니다.

var me = view[4].ant
var turf = view[4].color

var queenHolder = 2 // "Queen Holder", the turf colour for the queen in stage 3.
var queenBuild = 7 // "Queen Build", the turf colour for the queen in stage 2.
var antTrail = [3, 4, 5, 6] // Various colours of the ant's trails.
var orth = [1, 3, 5, 7] // Orthogonal Directions.
var rotates = [[1,3,5,7],[3,7,1,5],[5,1,7,3],[7,5,3,1]] // These are the orthogonal directions rotated so 0 is the first position, used in the queen build stage.
var outside = [1,2,3,5,6,7,8] // Every tile but the center one.
var diag = [0,2,6,8] // Diagonal Directions.

// Define a move function to avoid throwing an error.
function move(dir){
    if(view[dir].ant)   // If we're going to move onto an ant.
        dir = 4 // Don't move anywhere.
    if(view[dir].food && me.type < 5 && me.food > 0)    // If we're going to over-eat.
        dir = 4 // Don't move anywhere.
    return {cell: dir}  // Build the move output.
}

if(me.type == 5){ // If we're the queen.
    var invDiag = [8,6,2,0] // Inverse of diagonals, using the indexing of diag. So 0 becomes 8, and such.
    if(turf == 1 || turf == 8){
        // Stage 1.
        // Find enough food to start a hive.
        for(var i=0; i < view.length; i++){ // Check every tile in view
            if(view[i].food){   // Is it food?
                return move(i)  // Move to it.
            }
        }
        if(me.food > 3) // Do we have 4 food?
            return {cell:4, color:queenBuild}   // Move to stage 2.
        if(turf == 1)   // Are we on a white tile?
            return {cell:4, color:8}    // Set the tile to black.
        for(var i=0; i < diag.length; i++)  // Check all diagonals.
            if(view[diag[i]].color == 8)    // Is it black?
                return move(invDiag[i]) // Move in the opposite direction. This creates a straight diagonal line.
        return move(2)  // When in doubt, move randomly diagonally.
    }else if(turf == queenBuild){
        // Stage 2.
        // Spawn ants around, and set up their movement paths.
        if(me.food < 1) // Have we used all our food?
            return {cell:4, color:queenHolder}  // Move to stage 3.

        var firstHolder = -1; // Stores which way we're facing.
        for(var i=0; i < orth.length; i++){ // Check orthogonals.
            if(view[orth[i]].color == antTrail[0]){ // Is it the first trail colour?
                firstHolder = i // THIS WAY UP
                break;
            }
        }
        if(firstHolder==-1) // No way is up?
            return {cell:1, color:antTrail[0]} // Set a random direction to up.

        var orthRot = rotates[firstHolder]  // Get the rotated orthogonal set for the current up direction.
        for(var i=0; i < orthRot.length; i++){  // For each of them.
            if(!view[orthRot[i]].ant)   // Is there an ant on this tile yet?
                return {cell:orthRot[i], type:(i+1)}    // If not, place one down with the correct type.
            if(view[orthRot[i]].color!=antTrail[i]) // Otherwise, is the turf set correctly yet?
                return {cell:orthRot[i], color:antTrail[i]} // If not, set the turf.
        }
        return {cell:4, color:queenHolder}; // After all's said and done, move to stage 3. Probably won't happen this way.
    }else if(turf == queenHolder){
        // Stage 3.
        // Sit still, ensure rails exist around.

        var firstHolder = -1;   // Same behavoir of which way is up from stage 2.
        for(var i=0; i < orth.length; i++){
            if(view[orth[i]].color == antTrail[0]){
                firstHolder = i
                break;
            }
        }
        if(firstHolder==-1)
            return {cell:1, color:antTrail[0]}

        var orthRot = rotates[firstHolder]
        for(var i=0; i < orthRot.length; i++)   // Basically stage 2 without the spawning of ants.
            if(view[orthRot[i]].color!=antTrail[i])
                return {cell:orthRot[i], color:antTrail[i]}

        return {cell:4, color:queenHolder}  // And if there's nothing better to do, waste your time.
    }else{
        return {cell:4, color:1}    // We're lost, go back to stage 1, and try again.
        // I could probably add logic to check if we're stage 3 or something, but meh.
    }

}else{  // If we're a worker!

    for(var i=0; i < orth.length; i++)  // Check around.
        if(view[orth[i]].ant && view[orth[i]].ant.type == 5 && view[orth[i]].ant.friend && view[orth[i]].color == queenBuild)   // Is there a queen, in build mode, around us?
            return move(4)  // Wait politely for her to finish.

    var col = antTrail[me.type-1] // Which colour I use.

    if(me.food < 1){    // If we have no food.
        for(i=0; i < orth.length; i++){ // Check Orthogonals
            if(view[orth[i]].food){ // Is there food there?
                if(turf != col) // If we're not standing on our trail.
                    return {cell: 4, color: col}    // Place our trail here, so we can still find our way back.
                return move(orth[i])    // Otherwise, move to the food!
            }
        }
    }

    if(turf == col) // If we're sitting on our trail.
        return move(2) // Move off it randomly

    var corq = (t)=>t.color == col || (t.ant && t.ant.type == 5 && t.ant.friend)    // Helper function, does this tile contain our trail or the queen?
    var corqorf = (t)=>corq(t) || t.food    // Helper function, odes this tile contain our trail, the queen, or a piece of food?
    var queenInView = false;
    for(var i=0; i < view.length; i++)  // Check the entire view.
        if(view[i].ant && view[i].ant.type == 5 && view[i].ant.friend) // Can we see the queen?
            queenInView = true; // Remember this.

    // Using food > 0 behavoir if we see a queen, makes it so that we don't accidentally build our path over the queen or something silly.

    if(me.food > 0 || queenInView){ // If we have food, or we can see the queen.
        // DON'T build paths, just orbit our path clockwise.
        var orthmov = [3,7,1,5] // Directions to move if we see a path on an orthogonal.
        var diagC = [3,1,7,5]   // Directions to move if we see a path on a diagonal.
        for(var i=0; i < orth.length; i++)  // For each Orthogonal, which takes preference.
            if(corqorf(view[orth[i]]))  // Is there the queen, a trail, or food here?
                return move(orthmov[i]) // move CW to it.
        for(var i=0; i < diag.length; i++)  // Ditto for Diagonals.
            if(corqorf(view[diag[i]]))
                return move(diagC[i])

    }else{
        // EXTEND paths, or continue orbiting clockwise.
        var orthM = [0,6,2,8]   // Directions a path should be when we check an orthogonal.
        var orthMo = [3,7,1,5]  // Directions to move if we see an orthogonal, and the diagonal is there.
        var diagC = [3,1,7,5]   // Directions to place a path if we only see an orthogonal.
        for(var i=0; i < orth.length; i++){ // In each Orthogonal.
            var v = view[orth[i]]
            if(corq(v)){    // Is there a trial?
                if(corq(view[orthM[i]]))    // Is there a trail in the after it position?
                    return move(orthMo[i])  // Move in the correct direction.
                return {cell:orthM[i], color:col}   // Place the trail in the after it position.
            }
        }
        for(var i=0; i < diag.length; i++)  // Check diagonals as a last resort.
            if(corq(view[diag[i]])) // Is there a path /HERE/?
                return {cell:diagC[i], color:col}   // Place the respective diagonal's orthogonal.

    }
    return move(2)  // When we're lost, scamper around. Just like Trail-eraser wants us to.
}

이 플레이어는 토너먼트 게임에서 실격 처리되었으며 수정을 위해 수정 될 때까지 순위표에서 제외됩니다. 다음 의견에서 자세한 내용을 확인하십시오.
trichoplax

이유 : 음식 위에 새로운 노동자를 만들 수 없습니다. 입력 : [{ "color": 7, "food": 0, "ant": null}, { "color": 1, "food": 0, "ant": null}, { "color": 8, "food": 0, "ant": null}, { "color": 3, "food": 1, "ant": null}, { "color": 7, "food": 0, "ant": { "food": 1, "type": 5, "friend": true}}, { "color": 1, "food": 0, "ant": null}, { "color": 1, "음식 ": 0,"ant ": null}, {"color ": 1,"food ": 0,"ant ": null}, {"color ": 7,"food ": 0,"ant ": null} ] 응답 : { "cell": 3, "type":

3

로마 네 스코로드

이 플레이어는 노동자를 생산하지 않으며 여왕은 일직선으로 움직이며 방문한 각 칸을 표시합니다. 여왕은 방금 표시된 표시된 셀을 볼 수 있고 반대 방향으로 이동하여 직선을 확보하기 때문에 입력 보이는 셀의 임의의 방향에도 불구하고 직선 동작이 가능합니다.

답변의 첫 번째 코드 블록은 게임에 자동으로 포함됩니다.

// Full version that won't be disqualified for moving onto another ant

var i

// Color own cell if white
if (view[4].color === 1) {
    return {cell:4, color:3}
}

// Otherwise move to food if visible
for (i=0; i<9; i++) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to a white cell opposite a colored cell
for (i=0; i<9; i++) {
    if (view[i].color === 1 && view[8-i].color > 1 && !view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to an unoccupied cell
for (i=0; i<9; i++) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise don't move at all
return {cell:4}

다음은 다른 개미를 확인하지 않지만 다른 개미를 밟기 위해 실격 될 때까지 동일한 동작을하는 더 간단한 버전입니다.

// Basic version for an intuitive understanding

var i

// Color own cell if white
if (view[4].color === 1) {
    return {cell:4, color:3}
}

// Otherwise move to food if visible
for (i=0; i<9; i++) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to a white cell opposite a colored cell
for (i=0; i<9; i++) {
    if (view[i].color === 1 && view[8-i].color > 1) {
        return {cell:i}
    }
}

// Otherwise move "left and up", which will be a random direction
return {cell:0}

이 두 번째 코드 블록은 게임에서 선택되지 않습니다. 즉, 답변 설명의 일부로 추가 코드 블록을 포함 할 수 있습니다. 게임에서 경쟁하려는 코드 블록이 답의 첫 번째 코드인지 확인하십시오.

직선이 아닌 임의의 움직임을 생성하는 예는 Brownian Jig를 참조하십시오 .


3

빈스

9 개월이 지난 후에도 경기장은 여전히 ​​약간 부드러워 보인다고 생각하십니까?

Antdom Walking Artist 와 Orphan The Formation 워커가 매력적으로 꾸미는 데 약간의 도움을 줄 수 있다고 생각하십니까 ?

그럼 당신은 이것을 좋아할 것입니다!

개조 된 고속도로

우리의 수단이 허락하는대로 때때로 여왕은 화가 한두 명을 후원하고 낳을 것입니다. 이들은 주위의 색상을 다양한 개인 스타일로 엉망으로 만들며 종종 기존 색상을 고려하지만 적합하다고 생각되면 재정렬하고 비틀기합니다. 그들은 일반적으로 혼자 또는 때로는 쌍으로 작동합니다. (두 개미는 첫날과 Dave 's Forensic Ants 이래로 직선의 수평 또는 수직선을 따라갈 수 있었지만 이제는 한 세포의 가치만큼 만나는 패턴을 바꾸는 탠덤을 조심하십시오.)

클로드와 진

저렴한 가격으로 만들기 위해 풍차 에서 들어 올린 백본이 있습니다 . 결코 자라거나 정착하지 않는 풍차 여왕과 비서 / 네비게이터를 상상해보십시오. (이 아이디어는 뱀파이어 의 경비원 시설에 의해 개척 된 Lightspeed 에 의해 이전에 완성 되었습니다 . 그러나 구현은 Lightspeed와는 다릅니다.) 우리 자신의 자손에 부딪 칠 때 물건이 떨어지지 않도록 많은 수정이 필요했습니다. .

본질적 으로이 항목은 Lightspeed를 능가 할 수는 없지만 현재 (2018 년 4 월 현재) 경쟁자 중 약 5 분의 모든 사치에 잘 맞을 것으로 예상됩니다.

주석 처리되지 않은 소스 코드는 GitHub 에 있으며, 멋진 스크린 샷을 수집하기 위해 각 화가 유형과 스타일에 대한 세부 정보를 추가 할 계획입니다.

var ANV=1;var AMK=2;var AGS=3;var AWM=4;var AQ=5;var THC=1;var THP=[0,0,0,0,0,0];THP[AMK]=19;THP[AGS]=17;THP[AWM]=15;var RM=15;var SPDAT =[0,AMK,AGS,0,AWM,0,AGS,AWM,0,AMK,0,AWM,AMK,0,AGS];var PW=1;var PY=2;var PP=3;var PC=4;var PR=5;var PG=6;var PB=7;var PK=8;var LCLR=PW;var LT=PY;var LLSF=PG;var TN=8;var POSC=4;var NOP={cell:POSC};var CCW=[6,7,8,5,2,1,0,3,6,7,8,5,2,1,0,3,6,7,8,5,2,1];
var xn=-1;var here=view[POSC];var mC=here.color;var myself=here.ant;var mT=myself.type;var mF=myself.food;var mS=(mT!=AQ&&mF>0);var dOK=[true,true,true,true,true,true,true,true,true];
var uo=true;var sL=[0,0,0,0,0,0,0,0,0];var sD=[0,0,0,0,0,0,0,0,0];var sN=[0,0,0,0,0,0,0,0,0];var sT=[0,0,0,0,0,0,0,0,0];var fdL=0;var fdD=0;var fdT=0;sT[mC]++;for (var i=0; i<TN; i+=2){var cell=view[CCW[i]];sD[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdD++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}for (var i=1; i<TN; i+=2){var cell=view[CCW[i]];sL[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdL++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}var aF=[0,0,0,0,0,0];var aLF=[0,0,0,0,0,0];var aUF=[0,0,0,0,0,0];var fT=0;var mQ=0;var aE=[0,0,0,0,0,0];var aLE=[0,0,0,0,0,0];var aUE=[0,0,0,0,0,0];var eT=0;for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant){if (cell.ant.friend){aF[cell.ant.type]++;fT++;if (cell.ant.type==AQ){xn=i&6;mQ=i&1;}if (cell.ant.food>0){aLF[cell.ant.type]++;} else {aUF[cell.ant.type]++;}} else {aE[cell.ant.type]++;eT++;if (cell.ant.food>0){aLE[cell.ant.type]++;} else {aUE[cell.ant.type]++;}}dOK[CCW[i]]=false;uo=false;}}switch (mT){case AQ:return (rQSs());case ANV:return (rNSs());case AMK:return (rMSs());case AGS:return (rGSs());case AWM:return (rWSs());default:return NOP;}function rQSs(){switch (aF[ANV]){case 0:return (rQScrSy());case 1:for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.friend&&cell.ant.type==ANV){xn=i&6;if (i&1){return (rQLsSy());} else {return (rQCSy());}}}break;default:return (rQCNSy());}return NOP;}function rNSs(){if (aF[AQ]>0){if (mQ==1){return (rSLSy());} else {return (rNRSy());}} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else {return (rPPgSy());}}function rMSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AGS]+aF[AWM]>1){return (rPMgSy());} else if (aF[AGS]==1){return (rCPgSy());} else {return (rMPgSy());}}function rGSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AMK]+aF[AWM]>1){return (rPMgSy());} else if (aF[AMK]==1){return (rJPgSy());} else {return (rGPgSy());}}function rWSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AMK]+aF[AGS]>1){return (rPMgSy());} else {return (rWPgSy());}}function rQScrSy(){if (uo){if (fdT>0){return (rQSETc());} else if (mF>=THC){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+1],type:ANV};}}return {cell:1,type:ANV};} else if (mC!=LT){if ((mC==LCLR)||(sN[LCLR]>=TN-1)){return {cell:POSC,color:LT};} else {return (rQSTCTc());}} else if ((sN[LCLR]>=4)&&(sN[LT]==1)){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+4]};}}} else if (sN[LCLR]==TN){return {cell:0};} else {return (rQSATc());}} else {if ((fdT>0)&&(eT>0)&&(eT==aE[AQ])){return (rQSSTc());} else {return (rQSEvTc());}}return NOP;}function rQLsSy(){if ((sT[LCLR]<=2)&&(mF>1)&&(eT==0)){var artist=SPDAT[mF % RM];if ((artist!=0)&&(mF>=THP[artist])&&(aF[artist]<=1)){var tc=[6,2,4,5,3];for (var i=0; i<tc.length; i++){var c=CCW[xn+tc[i]];if (dOK[c]&&(view[c].food==0)){return {cell:c,type:artist};}}}}if ((eT==0)&&(fT==1)){if (view[CCW[xn+2]].food>0){return {cell:CCW[xn+2]};} else if ((view[CCW[xn+3]].food +view[CCW[xn+4]].food>0)&&(view[CCW[xn+1]].color!=LLSF)){return NOP;} else {return {cell:CCW[xn+2]};}} else if (dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else {return NOP;}}function rQCNSy(){for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.friend&&cell.ant.type==ANV){if (i&1){if (dOK[CCW[i-1]]){return {cell:CCW[i-1]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};} else if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return NOP;}} else {if (dOK[CCW[i+7]]){return {cell:CCW[i+7]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};} else if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return NOP;}}}}return (rQCSy());}function rQCSy(){return NOP;}function rSLSy(){if ((eT==0)&&(fT==1)){if (view[CCW[xn]].food>0){return {cell:CCW[xn]};} else if (view[CCW[xn+7]].food +view[CCW[xn+6]].food>0){return {cell:POSC,color:LLSF};} else {return {cell:CCW[xn]};}} else if ((eT>0)&&view[CCW[xn+2]].ant&&!view[CCW[xn+2]].ant.friend){return {cell:POSC,color:LLSF};} else if ((fT>1)&&((view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
(view[CCW[xn+6]].ant.food>0))||(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
(view[CCW[xn+5]].ant.food>0)))){return {cell:POSC,color:LLSF};} else {if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}return NOP;}function rNRSy(){if (view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&
(view[CCW[xn+1]].ant.type==mT)){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&(view[CCW[xn+7]].ant.type==mT)){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}}function rPPgSy(){if (aLF[AMK]+aLF[AGS] +aLF[AWM]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.food>0)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};}}}} else if (aF[mT]>0){return (rSPTc());}return (rPPgTc());}function rMPgSy(){if (aF[mT]>0){return (rSPTc());}return (rMPgTc());}function rGPgSy(){if (aF[mT]>0){return (rSPTc());}return (rGPgTc());}function rWPgSy(){if (aF[mT]>0){return (rSPTc());}return (rWPgTc());}function rCPgSy(){var phase=0;for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AGS)){xn=i&6;phase=i&1;break;}}if ((phase==1)&&(mC==view[CCW[xn+7]].color)&&(view[CCW[xn]].color==view[CCW[xn+1]].color)){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return {cell:CCW[xn+7],color:mC};}return NOP;}function rJPgSy(){var phase=0;for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AMK)){xn=i&6;phase=i&1;break;}}if (phase==0){if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return {cell:CCW[xn+3],color:mC};}return NOP;}function rPEgSy(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}function rPMgSy(){for (var i=0; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type!=mT)){if (dOK[CCW[i+1]]&&!view[CCW[i+7]].ant&&!view[CCW[i+2]].ant&&!view[CCW[i+3]].ant){return {cell:CCW[i+1]};} else if (dOK[CCW[i+7]]&&!view[CCW[i+1]].ant&&
!view[CCW[i+6]].ant&&!view[CCW[i+5]].ant){return {cell:CCW[i+7]};}}}for (var i=1; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type!=mT)){if (dOK[CCW[i-1]]&&!view[CCW[i+6]].ant){return {cell:CCW[i-1]};} else if (dOK[CCW[i+1]]&&!view[CCW[i+2]].ant){return {cell:CCW[i+1]};}}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return {cell:POSC,color:view[CCW[0]].color};}function rQSETc(){if (mC!=LT){return {cell:POSC,color:LT};}for (var i=0; i<TN; i++){if (view[CCW[i]].food>0){return {cell:CCW[i]};}}return NOP;}function rQSSTc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&(dOK[CCW[i]])){return {cell:CCW[i]};}}return NOP;}function rQSTCTc(){if ((mC!=LCLR)&&(sN[mC]>=4)){if (sN[LT]==0){return {cell:POSC,color:LT};} else if (sN[LT]>=3){return {cell:POSC,color:LT};} else {for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+2]].color!=LT)){return {cell:CCW[i+2],color:LT};}}return NOP;}} else if (sN[LT]==1){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+4]].color!=LCLR)){if (view[CCW[i+1]].color==LCLR){return { cell:CCW[i+1]};} else if (view[CCW[i+7]].color==LCLR){return { cell:CCW[i+7]};} else {return {cell:POSC,color:LT};}}}return {cell:POSC,color:LT};} else {return {cell:POSC,color:LT};}return NOP;}function rQSATc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LCLR)&&(view[CCW[i+1]].color==LCLR)&&(view[CCW[i+2]].color==LCLR)){if ((view[CCW[i+3]].color==LCLR)&&(view[CCW[i+4]].color==LCLR)){return {cell:CCW[i+2]};}return {cell:CCW[i+1]};}}for (var i=TN-1; i>=0; i--){if (view[CCW[i]].color!=LT){return {cell:CCW[i]};}}for (var i=0; i<TN; i++){if (view[CCW[i]].color!=LT){return {cell:CCW[i],color:LCLR};}}return {cell:0,color:LCLR};}function rQSEvTc(){if (sN[LT]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].color==LT){xn=i&6;}}if ( dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]] ){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+3]]&&dOK[CCW[xn+4]]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn]};} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]&&dOK[CCW[i+3]]&&dOK[CCW[i+4]]){return {cell:CCW[i+2]};}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]){return {cell:CCW[i+1]};}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}return NOP;}function rPPgTc(){if (sL[mC]==0){return {cell:1,color:mC};}for (var i=1; i<TN; i+=2){if (view[CCW[i]].color==mC){xn=i&6;break;}}var col1=(mC+1) % 8+1;if ((view[CCW[xn+5]].color==mC)&&(view[CCW[xn+3]].color==col1)&&(view[CCW[xn+7]].color!=col1)){xn=(xn+4) % 8;}if (view[CCW[xn+7]].color!=col1){return {cell:CCW[xn+7],color:col1};} else if (view[CCW[xn]].color!=col1){return {cell:CCW[xn],color:col1};}var col2=(mC+5) % 8+1;if (view[CCW[xn+3]].color!=col2){return {cell:CCW[xn+3],color:col2};} else if (view[CCW[xn+2]].color!=col2){return {cell:CCW[xn+2],color:col2};} else if (view[CCW[xn+5]].color!=mC){return {cell:CCW[xn+5],color:mC};} else if (view[CCW[xn+4]].color!=col2){return {cell:CCW[xn+4],color:col2};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return (rWgPTc());}}function rMPgTc(){switch (sT[mC]){case 9:var col=((mC+2) % 8)+1;return {cell:CCW[0],color:col};case 8:for (var i=0; i<TN; i++){var col=view[CCW[i]].color;if (col!=mC){if (i==0){return {cell:POSC,color:col};} else if ((i==1)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if ((i==2)&&dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else {return {cell:CCW[i-1],color:col};}}}break;case 7:return rWgPTc();case 6:for (var i=0; i<TN; i++){if (view[CCW[i]].color!=mC){if ((i==0)&&dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if ((i==1)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return {cell:CCW[i],color:mC};}}}break;case 5:case 4:case 3:for (var i=0; i<TN; i++){if (view[CCW[i]].color!=mC){return {cell:CCW[i],color:mC};}}break;case 2:case 1:default:for (var i=TN-1; i>=0; i--){var col=view[CCW[i]].color;if ((col==mC)&&(sT[view[CCW[i+4]].color]==7)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};}if (sT[col]>=3){return {cell:POSC,color:col};}}var col=view[CCW[1]].color;if (view[CCW[0]].color!=col){return {cell:CCW[0],color:col};} else if (view[CCW[2]].color!=col){return {cell:CCW[2],color:col};}break;}return (rWgPTc());}function rGPgTc(){var col=0;for (var c0=view[CCW[0]].color; c0<view[CCW[0]].color+8; c0++){var c=(c0 % 8)+1;if (sN[c]==0){col=c;}}if (col==0){return (rWgPTc());}for (var i=0; i<TN; i++){if (sN[view[CCW[i]].color]>1){return {cell:CCW[i],color:col};}}return (rWgPTc());}function rWPgTc(){var col=((mC+6) % 8)+1;if (sT[mC]==9){return {cell:CCW[0],color:col};}var myRand=(view[CCW[0]].color+sT[view[CCW[2]].color]) % 3;
switch (myRand){case 0:for (var i=0; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}break;case 1:if (view[CCW[1]].color!=view[CCW[7]].color){return {cell:CCW[1],color:view[CCW[7]].color};} else if (view[CCW[5]].color!=view[CCW[3]].color){return {cell:CCW[5],color:view[CCW[3]].color};}break;case 2:if (view[CCW[5]].color!=view[CCW[3]].color){return {cell:CCW[5],color:view[CCW[3]].color};} else if (view[CCW[1]].color!=view[CCW[7]].color){return {cell:CCW[1],color:view[CCW[7]].color};}break;default:break;}for (var i=1; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return (rWgPTc());}function rSPTc(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==mT)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if (dOK[CCW[i+2]]){return {cell:CCW[i+2]};} else if (dOK[CCW[i+6]]){return {cell:CCW[i+6]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}}return NOP;}function rWgPTc(){for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}

즐겨!

** v1.0.1 이제 엄격 모드 컨트롤러와 호환됩니다.

** v1.0.2 실격 오타를 수정합니다.


개미가 충분히 "창조적"이고 더 진보 된 개미를 혼동 할 수 있다면,이 항목은 실제로 Lightspeed를 능가 할 가능성이 있습니다-덜 강한 경쟁자 = 더 높은 점수. 비록 고속도로조차도 보통 예술가들의 치료에서 살아 남기 위해 관리하기 때문에 그것은 아마도 여기에 해당되지 않을 것입니다.
Alion

@Alion the VinceAnt 화가는 때때로 풍차 개미를 다른 사람들과 혼동하고 때로는 적의 노동자를 막거나 슬라이딩 광부 또는 풍차 광부가 잘못된 장소에서 새로운 레일을 시작하게 만듭니다. Lightspeed는 또한 다음과 같은 이점을 제공 할 것입니다.
GNiklasch

형성의 indev 버전은 적의 노동자 주위에 뭉쳐서 쓰레기로 채색하려고 시도하지만 이것이 항상 레일 벤딩으로 이어지는 것은 아닙니다. 그리고 그렇게하더라도 다른 노동자들이 여왕을 오가는 능력에 흠집이 생기는 경우는 드물다. 나에게서 가져 가라, 레일 둥지를 잘못 인도하는 것은 매우 어렵다.
eaglgenes101

@trichoplax 고정-죄송합니다.
GNiklasch

2

HalfThere

if(view[4].ant.type==5&&view[4].food>1)
{
    for(var i = 0; i<9; i++)
    {
        if(!view[i].ant)
        {
            return{cell:i,type: 1};
        }
    }
}
if(view[4].color != 3){
    return {cell: 4, color: 3};
}
for(var i = 0; i<9; i++)
{
    if(view[i].food==1)
    {
        return({cell:i})
    }

}


var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells



// Otherwise move to a white cell opposite a colored cell
for (i=0; i<4; i++) {
    j = (i+2) % 4
    if (view[orthogonals[i]].color === 1 &&
        view[orthogonals[j]].color > 1 && !view[orthogonals[i]].ant) {
        return {cell:orthogonals[i]}
    }
}

// Otherwise move to one of the vertical or horizontal cells if not occupied
for (i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}


for(var i = 0; i<9; i++)
{
    if(view[i].color==1)
    {
        return {cell:i};
    }
}
for(var i = 0; i<9; i++)
{
    if(view[i].ant==null)
    {
        return {cell:i};
    }
}

이 봇은 반쯤 있습니다 ... 기본적으로 그것은 단지 선을 만들고 직선으로 가고 다른 선이 보이면 조금 더듬습니다.

이것은 진행중인 작업입니다.


이것은 이국적인 환경에서 음식을 생산하는 노동자를 만들기 위해 실격 될 수 있습니다.
pppery

@ppperry 실제로는 할 수 없습니다. 절대 노동자를 만들지 않습니다 : /
Christopher

"작업자 생성"논리는 단지 죽은 코드이기 때문에 실제로는 불가능합니다. 여전히 지적 할 가치가 있습니다
pppery

나는 view[4].food > 1한 번 실수 한 데드 데드 체크 에 혼란 스러웠다
pppery

1
변경 view[4].food > 1view[4].ant.food > 1첫 번째 줄에
pppery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.