2048 Bot Challenge


19

Ми клонували 2048 рік, аналізуючи 2048 рік, але чому ми ще не зіграли його? Напишіть фрагмент JavaScript в 555 байт, щоб відтворити 2048 автоматично, найкращий рахунок буде врахований через годину (див. Бал нижче).

Налаштування:

Перейти до 2048 року та запустити:

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

a є об’єктом управління грою.

Правила:

Після налаштування ви можете запустити 555 байт JavaScript з консолі для керування грою. Вихідний код гри можна знайти тут (включаючи коментарі).

  • Він може робити лише ті речі, які можливі для користувача:
    • a.move(n) щоб запустити ключову дію в будь-якому з 4 напрямків.
      • 0: вгору, 1: праворуч, 2: вниз, 3: ліворуч
    • a.restart() щоб перезапустити гру. Перезапуск дозволений у середині гри.
  • Інформацію про стан гри можна знайти в a.grid.cells . Ця інформація доступна лише для читання
  • Допускається приєднання до будь-якої з функцій, будь-яка зміна їх поведінки не є (або змінюється будь-які інші дані)
  • Переміщення дозволено лише один раз кожні 250 хв

Приклад

Просто дуже простий приклад для початку. Без коментарів і вводить 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вище переможе так, але для його перемоги повинно вистачити однієї години:

  • Король Bottomstacker VII : 9912
  • Королева Bottomstacker V : 9216
  • Князь Bottomstacker II : 7520
  • Господь Bottom and Right : 6308
  • Селянин Randombot : 1413 рік
  • Bottomstacker IV: 12320 дискваліфіковано для здійснення двох рухів за один інтервал (протягом 250 мс)

FAQ

  • Чому цей виклик не є агностиком мови через термінал?
    • З тієї простої причини, що так веселіше. Перегляд графічної гри у самій грі просто набагато більше зачаровує, ніж бачити, як консоль випльовує номери. Навіть не знаючи JavaScript, ви повинні мати можливість приєднатися до цього завдання, оскільки мова йде не про особливості мови в першу чергу (просто використовуйте цей інструмент для мінімізації коду)

3
Схоже, що це просто кінець JavaScript-реалізацій найкращого алгоритму звідси , ні?
Джейсон C

2
-1 для ...best score after an hour will count... Чому всього годину?
користувач80551

3
У будь-якому випадку, я пропоную, в ім'я справедливості, посіяти генератор випадкових чисел однаковим для кожного тестового пробігу відповіді, а також виконувати жорсткий (1 година / 250 мс =) 14 400 рухів за пробіг, щоб усунути зміни цього рахунку, що належить до моменту неточностей. Принаймні результати можуть бути дещо детермінованішими та гідними KotH.
Джейсон C

1
750 байт чи 550 байт?
Пітер Тейлор

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

Він використовує стратегію, яку я також використовую.

EDIT: Приємно, він просто переміг ваш рахунок приблизно через 5 хвилин на моїй машині: D

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

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), c=4);
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);

EDIT: Оновлення: це просто побив мій особистий рекорд із досить шаленою оцінкою 12596.

EDIT: Ей, я знизу: 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 десь, що часто виконується. Я це колись.)

EDIT (знову ж таки): я відмовився від стандартного способу гри і повернувся до старого способу ведення справ. Зараз я тестую додаток, яке завжди злиється, якщо разом є дві плитки з 16 і більше:

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, щоб він перезапустив підрахунок після успішного переходу.
Девід Малдер

І дивлячись, як це грає зараз, треба сказати, це робить краще, ніж я очікував O :): D
Девід Малдер

Щойно помітив, що ви робите два рухи за один проміжок в останніх двох версіях, тому довелося дискваліфікувати зафіксований мною 12320 бал. І так, мені потрібна була якась назва: П
Девід Малдер

@DavidMulder Nooooooo! (Чи маєте ви якусь ідею, де це відбувається, щоб я міг це виправити?)
ʇǝɥʇıʎu 2s

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

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

Більш довга версія взагалі не була в гольфі (крім скорочення назв змінних), тому її можна було трохи скоротити, поки вона читається. Більш коротка версія була створена за допомогою компілятора закриття (спасибі за посилання!), Який закінчився у 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

( EDIT: Я залишив це деякий час довше, і він зміг деякі 7532моменти. Дарн, моя програма розумніша за мене ....)

Ще один цікавий примх: в одній із моїх скрутних спроб створити щось корисне, якимось чином закінчився так, що в будь-який час який дві плиток були в тому ж рядку або стовпці, вони були об'єднані. Це призвело до цікавих подій, оскільки випадкові 2-х або 4-х разів неодноразово поєднувалися з найвищою плиткою, щоразу подвоюючи її. Одного разу мені якось вдалося набрати понад 11000 за 15 секунд, перш ніж я його вимкнув .... XD

Будь-які пропозиції щодо вдосконалення дуже вітаються!


1

Стеклоочисники: 454 байти

Просто йде вправо, вгору, вліво, вгору ... повторюється (як і склоочисники на автомобілі), якщо воно не заклинило. Якщо вона заклинила, вона спробує вимкнути склоочисники і знову їх увімкнути. Найвищий бал, який я отримав за годину, склав 12156 - Однак, більшість балів десь від 3 до 7 к.

Він виводить бал на консоль після кожної спроби.

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

Як підказує заголовок, рухається вгору та вліво, викрадаючи роботу Девіда Малдера і міняючи деякі номери (я не знаю джек про 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.