2048ボットチャレンジ


19

私たちはされているクローニング、2048年の分析 2048が、なぜ我々はまだそれをプレイしていませんか?555バイトのJavaScriptスニペットを作成して2048を自動的に再生します。1時間後の最高スコアがカウントされます(以下のスコアリングを参照)。

セットアップ:

後藤2048と実行:

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

a ゲームを制御するオブジェクトです。

ルール:

セットアップ後、コンソールから555バイトのjavascriptを実行してゲームを制御できます。ゲームのソースコードはここにあります(コメントを含む)。

  • ユーザーに可能なことだけを行う場合があります。
    • a.move(n) 4つの方向のいずれかでキーアクションをトリガーします。
      • 0:上、1:右、2:下、3:左
    • a.restart() ゲームを再起動します。再起動は、ゲームの途中で許可されています。
  • ゲームの状態に関する情報はにありa.grid.cellsます。この情報は読み取り専用です
  • いずれかの関数へのフックは許可されますが、その動作を変更することはできません(または他のデータを変更します)
  • 移動は250msごとに1回のみ許可されます

開始するのは非常に簡単な例です。コメントなしで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 VII9912
  • クイーン Bottomstacker V9216
  • プリンス Bottomstacker II7520
  • Bottom and Right6308
  • 農民 Randombot1413
  • Bottomstacker IV12320 1つの間隔(250ミリ秒以内)で2つの動きを行うことはできませ

よくある質問

  • ターミナルを介した言語にとらわれないのはなぜですか?
    • このようにもっと楽しいという単純な理由で。ゲーム自体をグラフィカルに見るのは、コンソールが数字を吐き出すのを見るよりもはるかに魅力的です。javascriptがなくても、主に言語機能に関するものではないため、この課題に参加できるはずです(このツールを使用してコードを最小化してください)

3
これは、ここから最適なアルゴリズムのJavaScript実装の束になるだけのように思えますが、違いますか?
ジェイソンC

2
-1で...best score after an hour will count... なぜ1時間ですか?
user80551

3
いずれにせよ、公平性の名の下に、すべての回答のテスト実行に対して乱数ジェネレーターをシードし、実行ごとにハード(1時間/ 250 ms =)14,400の動きを実行して、そのカウントの変動を排除することをお勧めしますタイミングの不正確さ。少なくとも、結果はやや決定性があり、KotHに値する可能性があります。
ジェイソンC 14

1
750バイトまたは550バイト?
ピーターテイラー14

2
制限が強すぎます。750バイト、1時間、JavaScript。
TheDoctor

回答:


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

編集:1回だけではなく2回下に移動するのを忘れた、これはあなたが使用すべきコードです:

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

(実際には変更ではなく、単に圧縮されています。)

5回目は魅力ですか?わからない。いずれかの方法:

//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に追加すると、移動が成功した後にカウントを再開します。
デビッドモルダー14

D:そして、それは今プレー見て、私がO :)予想以上に良いやっている、と言うようになった
デヴィッド・モルダー

最後の2つのバージョンでは、1つの間隔で2つの動きをしていることに気付いたので、記録した12320スコアを失格にしなければなりませんでした。そしてええ、私は何らかの名前が必要でした:P
デビッドモルダー14

@DavidMulder Nooooooo!(私はそれを修正できるように、これがどこで起こるか
ご存知

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 14

3

どういうわけか、今朝この古いコンテストに出くわし、2048が大好きでAIが大好きで、JSは私が現在よく知っている数少ない言語の1つなので、試してみようと思いました。

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の合計が高いかどうか、およびすでに試行した方向に基づいて、移動する方向を決定します。右と下が最初の選択肢です。

これを振り返ってみると、いずれかの合計がゼロでない場合、タイルをその方向にスライドさせる最初の試みが成功することが保証されていることがわかりました。おそらく、これに基づいて移動決定セクションを最後に向かって簡略化できたでしょう。

私はこのプログラムを1時間実行したままにしたが、最終的には高得点になった6080。ただし、試用版の1つ(事前のミニファイ)では、6492最高のを管理しました6620。その論理は、数字が次のように積み重なる傾向があるため、時折左下に移動させることで大幅に改善できます。

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

編集:私はそれをしばらく実行し続け、いくつかの7532ポイントを管理しました。くそ、私のプログラムは私よりも賢い....)

もう1つの興味深いヒント:何か有用なものを作成しようとした私のグリッチな試みの1つで、どういうわけか、いつでも 2つのタイルは、それらが結合された、同じ行または列にありました。これにより、ランダムな2または4が最上位のタイルと繰り返し結合し、毎回2倍になるため、興味深い発展につながりました。ある時、シャットダウンする前に、なんとか15秒で11,000以上を記録することができました。...XD

改善の提案は大歓迎です!


1

フロントガラスワイパー:454バイト

ジャムにならない限り、単に右、上、左、上...を繰り返します(車のワイパーのように)。詰まった場合は、ワイパーをオフにして、再びオンにします。私が1時間で獲得した最高スコアは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();

デイヴィッド・モルダーのスクリプトと同様に、これも時々ターンごとに複数の動きを実行します。
jdstankosky 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.