Thử thách Bot 2048


19

Chúng tôi đã nhân bản năm 2048, phân tích năm 2048, nhưng tại sao chúng tôi chưa chơi nó? Viết đoạn mã javascript 555 byte để tự động phát 2048, điểm số tốt nhất sau một giờ sẽ được tính (xem cách ghi điểm bên dưới).

Thiết lập:

Đi đến 2048 và chạy:

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

a là đối tượng để điều khiển trò chơi.

Quy tắc:

Sau khi thiết lập, bạn có thể chạy 555 byte javascript từ bảng điều khiển để điều khiển trò chơi. Mã nguồn của trò chơi có thể được tìm thấy ở đây (bao gồm cả ý kiến).

  • Nó chỉ có thể làm những điều có thể cho người dùng:
    • a.move(n) để kích hoạt một hành động quan trọng theo bất kỳ hướng nào trong 4 hướng.
      • 0: lên, 1: phải, 2: xuống, 3: trái
    • a.restart() để khởi động lại trò chơi. Khởi động lại được cho phép ở giữa trò chơi.
  • Thông tin về trạng thái của trò chơi có thể được tìm thấy trong a.grid.cells. Thông tin này là chỉ đọc
  • Việc nối vào bất kỳ chức năng nào đều được cho phép, thay đổi hành vi của chúng theo bất kỳ cách nào là không (hoặc thay đổi bất kỳ dữ liệu nào khác)
  • Di chuyển chỉ được phép một lần trong mỗi 250ms

Thí dụ

Chỉ là một ví dụ rất đơn giản để bắt đầu từ. Không có ý kiến ​​và nhập 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);

Chấm điểm và kết quả

Tôi sẽ chạy đoạn trích trong một giờ liên tục và số điểm tốt nhất sẽ được tính. Thật vậy, có một cơ hội mà randombotở trên sẽ giành chiến thắng theo cách đó, nhưng 1 giờ là đủ để đánh bại nó:

  • Vua Bottomstacker VII : 9912
  • Nữ hoàng Bottomstacker V : 9216
  • Hoàng tử Bottomstacker II : 7520
  • Chúa Bottom and Right : 6308
  • Nông dân Randombot : 1413
  • Bottomstacker IV: 12320 Không đủ điều kiện để thực hiện hai lần di chuyển trong một khoảng thời gian (trong vòng 250ms)

Câu hỏi thường gặp

  • Tại sao thách thức này không phải là bất khả tri ngôn ngữ thông qua thiết bị đầu cuối?
    • Vì lý do đơn giản là nó vui hơn thế này. Xem một trò chơi tự chơi đồ họa đơn giản là mê hoặc hơn rất nhiều so với việc nhìn thấy một giao diện điều khiển phun ra những con số. Ngay cả khi không biết javascript, bạn vẫn có thể tham gia vào thử thách này vì chủ yếu không phải là về các tính năng ngôn ngữ (chỉ cần sử dụng công cụ này để giảm thiểu mã)

3
Điều này có vẻ như cuối cùng sẽ trở thành một loạt các triển khai JavaScript của thuật toán tốt nhất từ đây , phải không?
Jason C

2
-1 cho ...best score after an hour will count... Tại sao chỉ một giờ?
user80551

3
Trong mọi trường hợp, tôi đề nghị, nhân danh sự công bằng, gieo hạt cho trình tạo số ngẫu nhiên giống nhau cho mỗi lần chạy thử của câu trả lời và cũng chạy một cách khó khăn (1 giờ / 250 ms =) 14.400 di chuyển mỗi lần chạy để loại bỏ các biến thể của số đó do đến thời điểm không chính xác. Ít nhất các kết quả có thể mang tính quyết định và xứng đáng hơn với một KotH.
Jason C

1
750 byte hay 550 byte?
Peter Taylor

2
Quá hạn chế. 750 byte, 1 giờ, JavaScript.
TheDoctor

Câu trả lời:


4

Tôi không thể viết mã javascript, vì vậy tôi đã đánh cắp câu trả lời của bạn.

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

Nó sử dụng chiến lược tôi cũng sử dụng.

EDIT: Thật tuyệt, nó vừa đánh bại số điểm của bạn sau khoảng 5 phút trên máy của tôi: D

EDIT: Quên di chuyển xuống hai lần thay vì chỉ một lần, đây là mã bạn nên sử dụng:

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

Ngoài ra, có một lỗi trong đó là nó khởi động lại khi không cần thiết, nhưng tôi không chắc cách khắc phục. EDIT: Hiện tại nó có điểm cao là 3116 (sau 3 phút). Tôi nghĩ thật an toàn khi nói algoritm này tốt hơn là chỉ thực hiện các động tác ngẫu nhiên.

EDIT Phiên bản mới hơn:

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: Một phiên bản mới, phiên bản này di chuyển xuống trực tiếp sau khi di chuyển lên.

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: Cập nhật: nó vừa phá vỡ kỷ lục cá nhân của tôi với số điểm khá điên rồ là 12596.

EDIT: Hey, tôi là người bắt đáy: D Ngoài ra:

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

(Không thực sự là một sự thay đổi, chỉ là nén.)

Lần thứ 5 là một cơ duyên? Không chắc. Dù sao:

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

và:

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

Một phiên bản mới khác:

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

và:

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

(Tôi hy vọng nó không quá nhiều của một vấn đề mà điều này tiếp tục đằng sau màn hình gameover? Tôi nghĩ rằng bạn có thể thêm một a.over=0nơi nào đó được thực hiện thường xuyên. Tôi sẽ tìm ra một ngày nào đó.)

EDIT (một lần nữa): Tôi đã bỏ cách chơi trò chơi tiêu chuẩn và trở lại cách làm việc cũ. Bây giờ tôi đang thử nghiệm một bổ sung sẽ luôn hợp nhất nếu có 2 ô từ 16 trở lên cùng nhau:

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

Thêm vào mfs=0bên trong addRandomTile, theo cách đó nó sẽ khởi động lại đếm sau khi di chuyển thành công.
David Mulder

Và xem nó chơi ngay bây giờ, phải nói rằng, nó hoạt động tốt hơn tôi mong đợi O :): D
David Mulder

Chỉ cần lưu ý rằng bạn đang thực hiện hai động tác trong một khoảng thời gian trong 2 phiên bản gần nhất, vì vậy phải loại bỏ số điểm 12320 tôi đã ghi được. Và vâng, tôi cần một số loại tên: P
David Mulder

@DavidMulder Nooooooo! (Bạn có biết điều này xảy ra ở đâu không, để tôi có thể sửa nó?)
ɐɔIʇǝɥʇuʎs

13
Câu trả lời của bạn có đầy đủ phiên bản mới , vui lòng xóa mã lỗi thời. Hoặc giải thích sự khác biệt giữa các phiên bản. Mã cũ sẽ vẫn có thể truy cập được trong nhật ký "chỉnh sửa" nếu có ai quan tâm.
AL

3

Bot phải và xuống: 345 byte

Phiên bản ngắn

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

Phiên bản dài

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

Nói cách

Di chuyển xuống, sau đó phải, nếu bạn không thể di chuyển, di chuyển lên (hoặc nếu bạn không thể, di chuyển sang trái), nếu cả góc trên bên phải và dưới cùng bên phải được lấp đầy, di chuyển sang phải nếu không bắt đầu lại.

Điểm cao hiện tại

Điểm tốt nhất của riêng tôi là 7668, nhưng nó được chạy ở tốc độ lớn hơn nhiều so với t=250(và do đó gián tiếp dài hơn một giờ).


Kịch bản này có xu hướng thực hiện nhiều động tác mỗi lượt.
jdstankosky

3

Bằng cách nào đó tôi đã chạy qua cuộc thi cũ hơn này vào sáng nay và vì tôi yêu 2048, tôi yêu AI và JS là một trong số ít ngôn ngữ mà tôi hiện đang biết rõ, tôi nghĩ rằng tôi sẽ thử.

GreedyBot ( 607 536 byte)

Phiên bản ngắn:

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

Phiên bản dài (lỗi thời):

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

Phiên bản dài hơn hoàn toàn không được chơi gôn (ngoài việc thu nhỏ tên biến), vì vậy nó có thể được rút ngắn khá nhiều trong khi vẫn có thể đọc được. Phiên bản ngắn hơn được tạo bằng cách sử dụng Trình biên dịch đóng cửa (cảm ơn vì liên kết!), Kết thúc ở mức 650. Với một số sửa đổi tùy chỉnh từ phía tôi, tôi đã có thể loại bỏ 43 114 bit khác.

Về cơ bản, nó tìm kiếm thông qua lưới cho các di chuyển có thể, và bất cứ khi nào nó tìm thấy, sẽ thêm giá trị của nó vào tổng số ngang hoặc dọc. Sau khi tìm kiếm thông qua mọi di chuyển có thể, nó sẽ xác định hướng nào sẽ di chuyển, dựa trên tổng số H hoặc V cao hơn và các hướng mà nó đã thử. Phải và xuống là những lựa chọn đầu tiên.

Nhìn lại điều này, tôi nhận ra rằng nếu một trong hai tổng số khác không, thì nỗ lực đầu tiên trong việc trượt các ô theo hướng đó được đảm bảo để thành công. Có lẽ tôi có thể đơn giản hóa phần quyết định di chuyển đến cuối dựa trên điều này.

Tôi đã rời khỏi chương trình này trong một giờ và kết thúc với số điểm cao 6080. Tuy nhiên, trong một trong những lần chạy thử (trước khi thu nhỏ), nó đã đạt được số điểm cao 6492, chỉ sau 128 điểm tốt nhất của cá nhân tôi 6620. Logic của nó có thể được cải thiện đáng kể bằng cách thỉnh thoảng di chuyển xuống dưới, vì các con số có xu hướng chồng chất như thế này:

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

( EDIT: Tôi đã để nó chạy lâu hơn một chút và nó đã quản lý được một số 7532điểm. Darn, chương trình của tôi thông minh hơn tôi ....)

Một điều thú vị nữa: trong một trong những nỗ lực bị trục trặc của tôi trong việc tạo ra thứ gì đó có thể sử dụng được, bằng cách nào đó nó đã kết thúc để bất cứ lúc nào bất kỳ hai gạch nào nằm trong cùng một hàng hoặc cột, chúng được kết hợp. Điều này dẫn đến sự phát triển thú vị khi 2 hoặc 4 ngẫu nhiên sẽ liên tục kết hợp với ô cao nhất, tăng gấp đôi mỗi lần. Một lần, nó bằng cách nào đó đã đạt được hơn 11.000 trong 15 giây trước khi tôi tắt nó .... XD

Bất kỳ đề xuất cải tiến đều rất đáng hoan nghênh!


1

Cần gạt nước kính chắn gió: 454 byte

Đơn giản chỉ cần đi đúng, lên, trái, lên ... lặp lại (giống như cần gạt nước trên xe) trừ khi nó bị kẹt. Nếu nó bị kẹt, nó sẽ cố gắng tắt cần gạt nước và bật lại. Điểm cao nhất tôi đạt được trong một giờ là 12.156 - Tuy nhiên, hầu hết các điểm nằm trong khoảng từ 3k - 7k.

Nó sẽ xuất điểm số vào bảng điều khiển sau mỗi lần thử.

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

Như tiêu đề cho thấy, di chuyển lên và rời khỏi bằng cách đánh cắp công việc của David Mulder và hoán đổi một số số (Tôi không biết jack về Javascript, vì vậy tốt nhất tôi có thể làm là điều này).

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

Giống như kịch bản của David Mulder, điều này cũng thực hiện nhiều động tác mỗi lượt một lần.
jdstankosky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.