2048 봇 챌린지


19

우리는 2048 년을 복제하고 2048 년을 분석하고 있는데, 왜 아직 게임을하지 않았습니까? 2048을 자동으로 재생하려면 555 바이트 자바 스크립트 스 니펫을 작성하십시오. 1 시간 후 최고 점수가 계산됩니다 (아래 점수 참조).

설정:

고토 2048 및 실행 :

 a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);

a 게임을 제어하는 ​​객체입니다.

규칙 :

설정 후 콘솔에서 555 바이트의 자바 스크립트를 실행하여 게임을 제어 할 수 있습니다. 게임의 소스 코드는 여기 (주석 포함) 에서 찾을 수 있습니다 .

  • 사용자에게 가능한 일만 할 수 있습니다 :
    • a.move(n) 4 가지 방향으로 키 동작을 트리거합니다.
      • 0 : 위, 1 : 오른쪽, 2 : 아래, 3 : 왼쪽
    • a.restart() 게임을 다시 시작합니다. 게임 도중에 다시 시작할 수 있습니다.
  • 게임 상태에 대한 정보는에서 확인할 수 있습니다 a.grid.cells. 이 정보는 읽기 전용입니다
  • 어떤 방식 으로든 동작을 변경하는 것은 허용되지 않습니다 (또는 다른 데이터를 변경)
  • 250ms마다 한 번만 이동 가능

시작하는 아주 간단한 예입니다. 주석없이 181 바이트를 입력 합니다 .

//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  a.move(Math.floor(4 * Math.random()));
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

채점 및 결과

스 니펫을 1 시간 동안 계속 실행하면 최고 점수가 계산됩니다. 실제로 randombot위와 같은 방법으로 이길 가능성이 있지만 1 시간이면 충분합니다.

  • Bottomstacker VII : 9912
  • Bottomstacker V : 9216
  • 왕자 Bottomstacker II : 7520
  • 로드 Bottom and Right : 6308
  • 농민 Randombot : 1413
  • Bottomstacker IV: 12320 한 번의 간격 (250ms 이내)으로 두 번의 움직임으로 실격

자주하는 질문

  • 왜이 과제가 터미널을 통해 언어에 구애받지 않습니까?
    • 그것이 더 재미 있다는 간단한 이유 때문에. 게임이 그래픽으로 진행되는 것을 보는 것은 콘솔이 숫자를 뱉어내는 것을 보는 것보다 훨씬 더 매력적입니다. 자바 스크립트를 아는 것조차도 언어 기능에 관한 것이 아니기 때문에이 과제에 참여할 수 있어야합니다 ( 코드를 최소화 하기 위해이 도구 를 사용하십시오)

3
이것은 여기서 최고의 알고리즘의 JavaScript 구현으로 끝나는 것처럼 보입니다 .
Jason C

2
...best score after an hour will count... 왜 1 시간입니까?
user80551

3
어쨌든 공정성이라는 이름으로 난수 생성기를 모든 응답의 테스트 실행에 대해 동일하게 시드하고 실행 당 하드 (1 시간 / 250 ms =) 14,400 이동을 실행하여 해당 카운트의 변동을 제거하는 것이 좋습니다. 부정확 한 타이밍에. 최소한 결과는 다소 결정적이고 KotH에 합당 할 수 있습니다.
Jason C

1
750 바이트 또는 550 바이트?
피터 테일러

2
너무 제한적입니다. 750 바이트, 1 시간, JavaScript
TheDoctor

답변:


4

나는 자바 스크립트를 코딩 할 수 없으므로 귀하의 답변을 훔쳤습니다.

//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  a.move(c)
  c++
  if (c>3) {c=1}
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

그것은 또한 내가 사용하는 전략을 사용합니다.

편집 : 니스, 그것은 내 컴퓨터에서 약 5 분 후 점수를 이겼습니다 : D

편집 : 한 번이 아닌 두 번 아래로 이동하는 것을 잊었습니다.이 코드는 사용해야합니다.

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++

  if (c>4) {c=1} 
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

또한 필요하지 않을 때 다시 시작되는 버그가 있지만이 문제를 해결하는 방법을 잘 모르겠습니다. 편집 : 현재 최고 점수는 3116입니다 (3 분 후). 이 알고리즘이 임의의 동작을하는 것보다 낫다고 말하는 것이 안전하다고 생각합니다.

최신 버전 수정 :

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  m || mfs++;
  //up after 5 moves
  5 < mfs && (a.move(0));
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

편집 : 또 다른 새로운 버전,이 버전은 위로 이동 한 후 바로 아래로 이동합니다.

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  m || mfs++;
  //up after 5 moves
  5 < mfs && (a.move(0), c=4);
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

편집 : 업데이트 : 그것은 12596의 꽤 미친 점수로 내 개인 기록을 깨뜨 렸습니다.

편집 : 이봐, 나는 bottomstacker 해요 : D 또한 :

b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);m||mfs++;5<mfs&&(a.move(0),c=4);10<mfs&&(mfs=0,a.restart())},250);

(실제로는 변경이 아니라 압축 된 것입니다.)

다섯 번째 매력이야? 확실하지 않다. 어쨌든 :

//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  if (c==0) {c=4}
  m || mfs++;
  //up after 5 moves
  5 < mfs && (c=0);
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

과:

b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);0==c&&(c=4);m||mfs++;5<mfs&&(c=0);10<mfs&&(mfs=0,a.restart())},250);

또 다른 새로운 버전 :

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  if (c==0) {c=4}
  m || mfs++;
  //up after 5 moves
  5 < mfs && (c=0);
  //Found this in the source, as the criteria for a gameover. Might as well reset then ;)
  if (!a.movesAvailable()) {
      a.restart()
  }

}, 250);

과:

a=new GameManager(4,KeyboardInputManager,HTMLActuator,LocalStorageManager);b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);0==c&&(c=4);m||mfs++;5<mfs&&(c=0);a.movesAvailable()||a.restart()},250);

(게임 오버 화면 뒤에서 이것이 계속되는 문제가 아니기를 바랍니다. a.over=0 . 자주 실행 곳을 . 언젠가 알아낼 것입니다.)

편집 (다시) : 나는 표준 게임 오버 방식을 포기하고 옛날 방식으로 되돌 렸습니다. 이제 16 개 이상의 타일이 2 개 이상이면 항상 병합되는 추가 사항을 테스트하고 있습니다.

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() {
  m = !0;
  mfs = 0;
  b();
};
mfs = 0;
c = 1;
setInterval(function() {
  m = !1;
  l = 8;
  for (x = 0;x < 4;x++) {
    for (y = 0;y < 4;y++) {
      t1 = a.grid.cellContent({x:x, y:y});
      t2 = a.grid.cellContent({x:x, y:y + 1});
      t3 = a.grid.cellContent({x:x + 1, y:y + 1});
      if (t1 & t2) {
        if (t1.value == t2.value) {
          if (t1.value > l) {
            l = t1.value;
            c = 2;
          }
        }
        if (t1 & t3) {
          if (t1.value == t2.value) {
            if (t1.value > l) {
              l = t1.value;
            }
          }
        }
      }
    }
  }
  if (c <= 3) {
    n = c;
  } else {
    n = 2;
  }
  a.move(n);
  c++;
  if (c > 4) {
    c = 1;
  }
  if (c == 0) {
    c = 4;
  }
  m || mfs++;
  5 < mfs && (c = 0);
  10 < mfs && (mfs = 0, a.restart());
}, 250);

mfs=0내부 addRandomTile에 추가 하면 성공적인 이동 후 계산이 다시 시작됩니다.
David Mulder

그리고 지금 플레이하는 것을보고 말하면 O :) : D
David Mulder

지난 2 개의 버전에서 한 번에 두 번의 움직임을하고 있음을 알았으므로 내가 기록한 12320 점을 실격시켜야했습니다. 그리고 그래, 나는 어떤 종류의 이름이 필요했다 : P
David Mulder

@DavidMulder Nooooooo! (어떻게 이런 일이 발생하는지 알 수 있습니까? 제가 고칠 수 있습니까?)
ɐɔıʇǝɥʇuʎs

13
귀하의 답변이 새 버전 으로 가득 찼습니다 . 오래된 코드를 제거하십시오. 또는 버전 간의 차이점을 설명하십시오. 누군가 관심이 있다면 "편집"로그에서 이전 코드에 여전히 액세스 할 수 있습니다.
AL

3

오른쪽 및 아래쪽 봇 : 345 바이트

짧은 버전

b=a.addRandomTile.bind(a);m=!1;t=250;d=!0;a.addRandomTile=function(){m=!0;b();d&&setTimeout(c,t)};c=function(){d=!1;a.move(2);setTimeout(function(){m=!1;d=!0;a.move(1);m||setTimeout(function(){a.move(0);m?a.grid.cells[3][0]&&a.grid.cells[3][3]&&setTimeout(function(){a.move(1)},t):setTimeout(function(){a.move(3);m||a.restart()},t)},t)},t)};c();

긴 버전

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
t = 250;
d = !0;
a.addRandomTile = function() {
  m = !0;
  b();
  d && setTimeout(c, t);
};
c = function() {
  d = !1;
  a.move(2);
  setTimeout(function() {
    m = !1;
    d = !0;
    a.move(1);
    m || setTimeout(function() {
      a.move(0);
      m ? a.grid.cells[3][0] && a.grid.cells[3][3] && setTimeout(function() {
        a.move(1);
      }, t) : setTimeout(function() {
        a.move(3);
        m || a.restart();
      }, t);
    }, t);
  }, t);
};
c();

말로

아래로 이동 한 다음 오른쪽으로 움직일 수 없으면 위로 이동하거나 왼쪽으로 이동할 수 없습니다. 오른쪽 상단과 오른쪽 하단이 모두 채워지면 오른쪽으로 이동하고 다시 시작하십시오.

현재 최고 점수

내 자신의 최고 점수는 7668이지만 그것은 훨씬 더 빠른 속도로 t=250(따라서 간접적으로 1 시간보다 길었습니다).


이 스크립트는 한 턴에 여러 번 이동하는 경향이 있습니다.
jdstankosky

3

어떻게 든 오늘 아침 에이 오래된 대회를 만났고 2048을 좋아하기 때문에 AI를 좋아하고 JS는 현재 잘 알고있는 몇 가지 언어 중 하나입니다.

욕심 봇 ( 607) 536 바이트)

짧은 버전 :

C=function(x,y){return a.grid.cellContent({x:x,y:y})},h=[[1,3,2,0],[2,1,3,0]],V='value',A='addRandomTile';a=new GameManager(4,KeyboardInputManager,HTMLActuator,LocalStorageManager);b=a[A].bind(a);m=!1;f=d=X=Y=0;a[A]=function(){m=!0;f=0;b()};setInterval(function(){m=!1;for(var c=X=Y=0;4>c;c++)for(var e=0;4>e;e++)if(u=C(c,e),!!u){for(q=e+1;4>q;){v=C(c,q);if(!!v){u[V]==v[V]&&(Y+=u[V]);break}q++}for(q=c+1;4>q;){v=C(q,e);if(!!v){u[V]==v[V]&&(X+=u[V]);break}q++}}f<4&&a.move(h[X>Y+4?0:1][f]);m&&(f=0);m||f++;15<f&&(f=0,a.restart())},250);

긴 버전 (오래된) :

a = new GameManager(4, KeyboardInputManager, HTMLActuator,    LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
f = d = X = Y = 0;
a.addRandomTile = function() { m = !0; f = 0; b(); };
setInterval(function() {
    m = !1;
    X = Y = 0;

    for(var x=0;x<4;x++) {
        for(var y=0;y<4;y++) {
            u = a.grid.cellContent({x:x, y:y});
            if(u==null){continue;}
            q = y+1;
            while(q < 4) {
                v = a.grid.cellContent({x:x,y:q});
                if(v!=null){
                    if(u.value==v.value){
                        Y+=u.value;
                    }
                    break;
                }
                q++;
            }
            q = x+1;
            while(q < 4) {
                v = a.grid.cellContent({x:q,y:y});
                if(v!=null){
                    if(u.value==v.value){
                        X+=u.value;
                    }
                    break;
                }
                q++;
            }
        }
    }

    if(X>=Y){
        if(f==0)
            a.move(1);
        else if(f==1)
            a.move(3);
        else if(f==2)
            a.move(2);
        else if(f==3)
            a.move(0);
    } else {
        if(f==0)
            a.move(2);
        else if(f==1)
            a.move(0);
        else if(f==2)
            a.move(1);
        else if(f==3)
            a.move(3);
    }
    if(m)f=0;
    m || f++;
    if(15 < f) f=0,a.restart();
}, 250);

더 긴 버전은 변수 이름을 줄이는 것 외에는 전혀 골치 거리지 않았으므로 읽을 수있는 동안 상당히 단축 될 수 있습니다. 더 짧은 버전은 Closure Compiler (링크 덕분에!)를 사용하여 만들어졌으며 650으로 끝났습니다. 일부 사용자 정의 수정으로 다른 43 가지를 제거 할 수있었습니다. 114 비트.

기본적으로 그리드를 통해 가능한 이동을 검색하고 찾을 때마다 가로 또는 세로 합계에 값을 추가합니다. 가능한 모든 이동을 검색 한 후 H 또는 V 총계가 더 높은지 여부와 이미 시도한 방향에 따라 이동 방향을 결정합니다. 오른쪽과 아래가 첫 번째 선택입니다.

이것을 되돌아 보면, 나는 어느 쪽의 합계가 0이 아닌 경우, 타일을 그 방향으로 슬라이딩하려는 첫 번째 시도가 성공한다는 것을 알았습니다. 아마도 이것을 바탕으로 끝을 향한 이동 결정 섹션을 단순화 할 수 있습니다.

이 프로그램을 한 시간 동안 실행하고 높은 점수를 얻었습니다 6080. 그러나 시범 운영 (사전 최소화) 중 하나에서 6492내 개인 최고 기록보다 겨우 128 만 높은 점수를 기록했습니다 6620. 숫자가 다음과 같이 쌓이는 경향이 있으므로 때때로 왼쪽 아래로 이동하여 논리를 크게 향상시킬 수 있습니다.

 2  4  8 16
 4  8 16 32
 8 16 32 64
16 32 64 128

( 편집 : 나는 그것을 더 오래 실행하고 약간의 7532포인트를 관리했습니다 . Darn, 내 프로그램은 나보다 똑똑합니다 ....)

하나 더 재미있는 맛있는 가벼운 음식 : 뭔가 쓸모를 만드는에서 내 glitched 시도 하나, 어떻게 든 그렇게 그 언제 결국 어떤 두 개의 타일이 같은 행 또는 열 있었다, 그들은이 결합되었다. 이로 인해 임의의 2 또는 4가 반복적으로 가장 높은 타일과 결합하여 매번 두 배가되는 흥미로운 개발이 이루어졌습니다. 한번은 15 초 만에 11,000 점 이상을 득점했다 .... XD

개선을위한 제안은 매우 환영합니다!


1

앞 유리 와이퍼 : 454 바이트

끼어 들지 않으면 오른쪽, 위, 왼쪽, 위 ... 반복 (자동차의 와이퍼처럼) 반복합니다. 용지 걸림이 발생하면 와이퍼를 껐다가 다시 켜려고합니다. 한 시간 안에 얻은 최고 점수는 12,156입니다. 그러나 대부분의 점수는 3k-7k 사이입니다.

시도 할 때마다 점수를 콘솔에 출력합니다.

var move = !1;
var bad = 0;
var c = 0;
var b = a.addRandomTile.bind(a);
a.addRandomTile = function() {
    b();
    move=!0;
    bad=0;
}
setInterval(function() {
    if (!move) bad++;
    if (c>3) c=0;
    move = !1;
    if (c==3) {a.move(0);c++;}
    if (c==2) {a.move(3);c++;}
    if (c==1) {a.move(0);c++;}
    if (c==0) {a.move(1);c++;}
    if (bad>10) {a.move(2);}
    if (!a.movesAvailable()) {console.log("Score: "+a.score);a.restart();}
}, 250);

0

UpAndLeftBot

제목에서 알 수 있듯이 David Mulder의 작업 을 훔치고 숫자를 바꾸면 위아래로 움직 입니다 (Javascript에 대한 잭을 모르므로 최선을 다할 수 있습니다).

a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
t = 250;
d = !0;
a.addRandomTile = function() {
  m = !0;
  b();
  d && setTimeout(c, t);
};
c = function() {
  d = !1;
  a.move(0); // a.move(2)
  setTimeout(function() {
    m = !1;
    d = !0;
    a.move(3); // a.move(1)
    m || setTimeout(function() {
      a.move(2);  //a.move(0)
      m ? a.grid.cells[3][0] && a.grid.cells[3][3] && setTimeout(function() {
        a.move(3); // a.move(1)
      }, t) : setTimeout(function() {
        a.move(1);  // a.move(3)
        m || a.restart();
      }, t);
    }, t);
  }, t);
};
c();

David Mulder의 스크립트와 마찬가지로 회 전당 한 번에 여러 번의 이동도 수행합니다.
jdstankosky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.