2048 Bot Challenge

19

Kami telah mengkloning 2048, menganalisis 2048, tetapi mengapa kami belum memainkannya? Tulis snipet javascript 555 byte untuk bermain 2048 secara otomatis, skor terbaik setelah satu jam akan dihitung (lihat skor di bawah).

Mempersiapkan:

Goto 2048 dan jalankan:

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

a adalah objek untuk mengontrol permainan.

Aturan:

Setelah pengaturan, Anda dapat menjalankan 555 byte javascript dari konsol untuk mengontrol permainan. Kode sumber permainan dapat ditemukan di sini (termasuk komentar).

  • Itu hanya dapat melakukan hal-hal yang memungkinkan bagi pengguna:
    • a.move(n) untuk memicu aksi kunci di salah satu dari 4 arah.
      • 0: atas, 1: kanan, 2: bawah, 3: kiri
    • a.restart() untuk memulai kembali game. Restart diperbolehkan di tengah permainan.
  • Informasi tentang keadaan permainan dapat ditemukan di a.grid.cells . Informasi ini hanya baca
  • Mengaitkan ke salah satu fungsi diizinkan, mengubah perilaku mereka dengan cara apa pun tidak (atau mengubah data lain)
  • Pindah hanya diperbolehkan sekali setiap 250ms

Contoh

Hanya contoh yang sangat sederhana untuk memulai. Tanpa komentar dan memasukkan 181 byte .

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

Penilaian dan hasil

Saya akan menjalankan cuplikan selama satu jam berturut-turut dan skor terbaik akan dihitung. Memang ada kemungkinan bahwa di randombotatas akan menang seperti itu, tetapi 1 jam harus cukup untuk mengalahkannya:

  • Raja Bottomstacker VII : 9912
  • Ratu Bottomstacker V : 9216
  • Pangeran Bottomstacker II : 7520
  • Tuhan Bottom and Right : 6308
  • Petani Randombot : 1413
  • Bottomstacker IV: 12320 didiskualifikasi untuk membuat dua gerakan dalam satu interval (dalam 250ms)

Faq

  • Mengapa tantangan ini bukan agnostik bahasa melalui terminal?
    • Untuk alasan sederhana bahwa ini lebih menyenangkan seperti ini. Menonton permainan itu sendiri secara grafis jauh lebih memikat daripada melihat konsol yang mengeluarkan angka. Bahkan tanpa mengetahui javascript Anda harus dapat bergabung ke dalam tantangan ini karena ini bukan tentang fitur bahasa terutama (cukup gunakan alat ini untuk meminimalkan kode)
David Mulder
sumber
3
Ini sepertinya hanya akan menjadi sekelompok implementasi JavaScript dari algoritma terbaik dari sini , bukan?
Jason C
2
-1 untuk ...best score after an hour will count... Mengapa hanya satu jam?
user80551
3
Dalam kasus apa pun, saya sarankan, atas nama keadilan, menyemai generator angka acak yang sama untuk setiap uji coba jawaban, dan juga menjalankan hard (1 jam / 250 ms =) 14.400 gerakan per lari untuk menghilangkan variasi jumlah yang dihitung karena untuk ketidaktepatan waktu. Setidaknya hasilnya bisa agak lebih deterministik dan layak untuk sebuah KotH.
Jason C
1
750 byte atau 550 byte?
Peter Taylor
2
Terlalu membatasi. 750 byte, 1 jam, JavaScript.
TheDoctor

Jawaban:

4

Saya tidak bisa kode javascript, jadi saya mencuri jawaban Anda.

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

Itu menggunakan strategi yang juga saya gunakan.

EDIT: Bagus, baru saja mengalahkan skor Anda setelah sekitar 5 menit di mesin saya: D

Sunting: Lupa untuk turun dua kali alih-alih hanya sekali, ini adalah kode yang harus Anda gunakan:

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

Juga, ada bug di dalamnya yang restart ketika tidak diperlukan, tapi saya tidak yakin bagaimana cara memperbaikinya. EDIT: Saat ini memiliki skor tertinggi 3116 (setelah 3 menit). Saya pikir aman untuk mengatakan algoritme ini lebih baik daripada hanya melakukan gerakan acak.

EDIT Versi yang lebih baru:

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

EDIT: Versi baru lainnya, versi ini langsung turun setelah naik.

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

EDIT: Perbarui: itu baru saja memecahkan rekor pribadi saya dengan skor yang cukup gila di 1.2596.

EDIT: Hei, saya bottomstacker: D Juga:

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

(Sebenarnya bukan perubahan, hanya dikompresi.)

5 kali pesona? Tidak yakin. Bagaimanapun:

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

dan:

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

Versi baru lainnya:

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

dan:

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

(Saya harap ini tidak terlalu menjadi masalah bahwa ini terus berlanjut di belakang layar gameover? Saya pikir Anda bisa menambahkan a.over=0tempat yang sering dieksekusi. Saya akan mencari tahu suatu hari nanti.)

EDIT (lagi): Saya membuang cara permainan standar dan kembali ke cara lama dalam melakukan sesuatu. Saya sekarang menguji tambahan yang akan selalu digabung jika ada 2 ubin yang terdiri dari 16 atau lebih bersama-sama:

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);
ɐɔıʇǝɥʇu
sumber
Tambahkan mfs=0di dalam addRandomTile, dengan cara itu akan memulai kembali penghitungan setelah langkah yang berhasil.
David Mulder
Dan menontonnya diputar sekarang, bisa dikatakan, itu lebih baik dari yang saya harapkan O :): D
David Mulder
Hanya perhatikan bahwa Anda membuat dua gerakan dalam satu interval dalam 2 versi terakhir, jadi harus mendiskualifikasi skor 12320 yang telah saya rekam. Dan ya, saya perlu semacam nama: P
David Mulder
@DavidMulder Nooooooo! (Apakah Anda tahu di mana hal ini terjadi, sehingga saya dapat memperbaikinya?)
Aprıʇǝɥʇuʎs
13
Jawaban Anda penuh dengan versi baru , harap hapus kode yang sudah usang. Atau jelaskan perbedaan antar versi. Kode lama masih dapat diakses di log "edit" jika ada yang tertarik.
AL
3

Bot Kanan dan Bawah: 345 byte

Versi pendek

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

Versi panjang

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

Dalam kata kata

Bergerak ke bawah, lalu ke kanan, jika Anda tidak dapat bergerak, bergerak ke atas (atau jika Anda tidak bisa, bergerak ke kiri), jika kedua sudut kanan atas dan kanan bawah terisi, bergerak ke kanan jika tidak memulai dari awal.

Skor tertinggi saat ini

Skor terbaik saya sendiri adalah 7668, tetapi itu berjalan pada kecepatan yang jauh lebih besar daripada t=250(dan dengan demikian secara tidak langsung lebih dari satu jam).

David Mulder
sumber
Skrip ini memiliki kecenderungan untuk melakukan beberapa gerakan per giliran.
jdstankosky
3

Entah bagaimana saya berlari melintasi kontes yang lebih tua pagi ini, dan karena saya suka 2048, saya suka AI, dan JS adalah salah satu dari sedikit bahasa yang saat ini saya kenal dengan baik, saya pikir saya akan mencobanya.

GreedyBot ( 607 536 bytes)

Versi pendek:

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

Versi panjang (kedaluwarsa):

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

Versi yang lebih panjang sama sekali tidak golf (selain menyusutkan nama variabel), sehingga bisa disingkat sedikit saat masih dapat dibaca. Versi yang lebih pendek dibuat menggunakan Closure Compiler (terima kasih atas tautannya!), Yang berakhir pada 650. Dengan beberapa modifikasi khusus pada bagian saya, saya dapat mencukur 43 lagi. bit 114 yang .

Pada dasarnya, ia mencari melalui kisi-kisi untuk kemungkinan gerakan, dan setiap kali menemukannya, menambah nilainya ke total horizontal atau vertikal. Setelah mencari melalui setiap gerakan yang mungkin, ia menentukan arah mana yang harus bergerak, berdasarkan pada apakah total H atau V lebih tinggi, dan arah yang telah dicoba. Kanan dan Bawah adalah pilihan pertama.

Melihat ke belakang pada hal ini, saya menyadari sekarang bahwa jika salah satu totalnya bukan nol, upaya pertama untuk menggeser ubin ke arah itu dijamin berhasil. Mungkin saya bisa menyederhanakan bagian penentu langkah menuju akhir berdasarkan ini.

Saya meninggalkan program ini berjalan selama satu jam dan berakhir dengan skor tinggi 6080. Namun, dalam salah satu uji coba (pra-minifikasi), itu berhasil skor tinggi 6492, hanya 128 di belakang terbaik pribadi saya 6620. Logikanya bisa sangat ditingkatkan dengan membuatnya bergerak ke kiri sesekali, karena jumlahnya cenderung menumpuk seperti ini:

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

( EDIT: Saya membiarkannya berjalan lebih lama, dan berhasil beberapa 7532poin. Sial, program saya lebih pintar dari saya ....)

Satu berita gembira yang lebih menarik: dalam salah satu upaya saya yang salah dalam menciptakan sesuatu yang bisa digunakan, entah bagaimana itu berakhir sehingga setiap kali dua ubin berada di baris atau kolom yang sama, mereka digabungkan. Hal ini menyebabkan perkembangan menarik karena 2s atau 4s acak akan berulang kali bergabung dengan ubin tertinggi, menggandakannya setiap waktu. Suatu kali, entah bagaimana berhasil mencetak lebih dari 11.000 dalam 15 detik sebelum saya mematikannya .... XD

Setiap saran untuk perbaikan sangat kami harapkan!

Produksi ETH
sumber
1

Wiper Kaca Depan: 454 byte

Langsung saja Kanan, Atas, Kiri, Atas ... berulang (seperti wiper pada mobil) kecuali macet. Jika macet, ia akan berusaha mematikan wiper dan menyalakannya kembali. Skor tertinggi yang saya dapatkan dalam satu jam adalah 12.156 - Namun, sebagian besar skor berada di antara 3k - 7k.

Ini akan menampilkan skor ke konsol setelah setiap upaya.

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);
jdstankosky
sumber
0

UpAndLeftBot

Seperti judulnya, bergerak ke atas & kiri dengan mencuri karya David Mulder & bertukar beberapa nomor (saya tidak tahu jack tentang Javascript, jadi yang terbaik yang bisa saya lakukan adalah ini).

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();
Kyle Kanos
sumber
Sama seperti skrip David Mulder, ini juga melakukan beberapa gerakan per belokan sesekali.
jdstankosky