2048机器人挑战赛


19

我们一直在克隆 2048,分析 2048,但是为什么我们还没有播放呢?编写一个555字节的javascript代码段以自动播放2048,一个小时后的最佳得分将起作用(请参阅下面的得分)。

设定:

转到2048并运行:

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

a 是控制游戏的对象。

规则:

设置完成后,您可以从控制台运行555字节的JavaScript,以控制游戏。您可以在此处找到游戏的源代码(包括注释)。

  • 它只能做用户可能做的事情:
    • a.move(n) 在四个方向中的任何一个上触发按键动作。
      • 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);

计分和结果

我将连续运行一小时的摘录,并将获得最高分。确实有可能randombot以上者会以这种方式获胜,但是1小时就足以击败它:

  • 国王 Bottomstacker VII9912
  • 女王 Bottomstacker V9216
  • 王子 Bottomstacker II7520
  • 领主 Bottom and Right6308
  • 农民 Randombot1413
  • Bottomstacker IV12320 不合格,不得在一个间隔内进行两次移动(250毫秒内)

常问问题

  • 为什么此挑战无法通过终端与语言无关?
    • 出于这样的简单原因,它更有趣。以图形方式观看游戏本身比看到控制台吐出更多的数字更令人着迷。即使不了解javascript,您也应该能够加入这一挑战,因为它主要与语言功能无关(只需使用此工具以最小化代码)

3
似乎最终将是这里最好的算法的一堆JavaScript实现,不是吗?
Jason C

2
-1 ...best score after an hour will count... 为什么只需要一个小时?
2014年

3
无论如何,我建议以公平为名,为每个答案的测试运行播种相同的随机数生成器,并每次运行(1小时/ 250毫秒=)14,400次辛苦操作,以消除应计的偏差计时不准确。至少结果可能更具确定性,值得KotH使用。
詹森C

1
750个字节还是550个字节?
彼得·泰勒

2
太严格了。750字节,1小时,JavaScript。
TheDoctor 2014年

Answers:


4

我无法编写JavaScript代码,所以我偷了你的答案。

//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分钟后)。我认为可以肯定地说这种算法要比随机移动更好。

EDIT较新版本:

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经常执行的地方。我有一天会解决这个问题。)

编辑(再次):我放弃了标准的gameover方法,并恢复为旧的工作方式。我现在正在测试一个添加项,如果有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=0inside addRandomTile,这样成功移动后它将重新开始计数。
大卫·穆尔德

现在观看比赛,它的表现比我预期的要好O :):D
David Mulder 2014年

刚注意到您在最近2个版本中以一个间隔进行了两次移动,因此不得不取消我记录的12320得分。是的,我需要某种名称:P
David Mulder 2014年

@DavidMulder Nooooooo!(您知道这种情况会发生在哪里,以便我可以解决吗?)
ɐɔıʇǝɥʇuʎ2014年

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(因此间接超过一个小时)。


该脚本倾向于每转执行多次移动。
jdstankosky 2014年

3

今天早上我以某种方式参加了这个较早的比赛,由于我喜欢2048,所以我喜欢AI,而JS是我目前所熟知的少数几种语言之一,所以我想尝试一下。

GreedyBot(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合计是否更高以及已尝试的方向来确定应移动的方向。正确和正确是第一选择。

回顾这一点,我现在意识到,如果任何一个总数都不为零,则可以保证在该方向上滑动磁贴的第一次尝试将成功。也许我可以基于此简化到最后的移动决定部分。

我让该程序运行了一个小时,结果得分很高6080。但是,在其中一项试运行(预缩小)中,它的得分很高6492,仅落后于我个人最好的128 分6620。通过不时地向下移动它,可以大大改善其逻辑,因为数字往往像这样堆积:

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

编辑:我让它运行了更长的时间,并且它管理了一些7532问题。该死,我的程序比我更聪明。...)

另一个有趣的花絮:在我尝试创建可用的东西的一种小尝试中,它最终以某种方式结束了,以便在任何两个图块位于同一行或同一列中时,将它们组合在一起。这导致了有趣的发展,因为随机的2s或4s将反复与最高的图块组合,每次都将其加倍。有一次,在我关闭它之前,它以某种方式在15秒内得分超过11,000。

任何改进的建议都非常欢迎!


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的作品并交换一些数字来上下移动(我不知道Java语言的杰克,所以我能做的就是这个)。

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 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.