Tetris на javascript (в 30+ строк)

    Решил поддержать тему!
    image
    Тетрис в 30+ строк js кода.
    • Знает все фигуры тетриса
    • Управление с клавиатуры
    • ВВЕРХ — фигурки крутятся по часовой стрелке
    • ВНИЗ — ускорить падение
    • Скорость падания постепенно увеличивается
    • Очки подсчитываются

    ссылка на jsfiddle

    Принцип работы.

    1. Получаем фигурки
    Все фигурки хранятся в переменной fs=«1111:01|01|01|01*011|110:010|011|001*...» в виде строки. Чтобы получить массив фигур — делаем split('*'), далее в каждой фигуре есть от 1-го (для «палки») до 4-х (для L, Г и «пирамидки») состояния (чтобы их можно было переворачивать) — они разделены ":" — соответственно чтобы получить одно состояние — split(':'). Допустим получили «пирамидку» — «010|111», здесь делаем split('|') — и получаем уже конечный двумерный массив для одного состояния одной фигуры. «0»- пустое пространство (не нужно отрисовывать), «1» — нужно рисовать.

    2. Всё перемещение фигур делается двумя функциями — «стереть фигуру» и «попытаться построить».
    При любых перемещениях вправо-влево или вниз, или даже переворот фигуры — сначала стираем текущую отображаемую фигуру, потом пытаемся построить фигуру на новом месте — если при постройке какой-то из квадратиков вылазит за край «стакана», или попадает на место, где уже есть заполненный квадратик от предыдущих фигур — стираем «активную фигуру», и стоим ее на предыдущем месте.

    3. Перемещения делаются с клавиатуры. По таймеру просто вызывается функция, которая обрабатывает нажатия с клавиатуры с кодом кнопки ВНИЗ. При каждом вызове таймаута — время до вызова уменьшается.

    4. Если не удалось переместить фигуру вниз — значит она уперлась в предыдущие фигуры или дно. В таком случае проверяем нет ли заполненных строк, и рисуем новую фигуру вверху стакана. Если вверху стакана нарисовать фигуру не удалось — игра закончена!
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 44

    • UFO just landed and posted this here
        +2
        Извиняюсь перед читателями, просто уже был третий час ночи — не было сил писать. Сейчас исправлюсь!
          +1
          Утро вечера мудренее (с) Народная мудрость
        +5
        Я знал, я знал, что тетрис следующий:)
      • UFO just landed and posted this here
          0
          Да я это и сам понимаю… и так то код не совсем честный на 30 строк. Боролся между двумя чувствами — сделать код покороче и не совсем страшным в плане оформления. В итоге ни то, ни другое не выдержал.
          +3
          а где длинная??? я ее так ждал…
          • UFO just landed and posted this here
              +27
              Игорь, у вас ведь так же?

              image
              • UFO just landed and posted this here
            –1
            Форматирование какое-то читерское + топики были про 30 строчники, а у вас 35.
              0
              Так, что там ещё осталось из потенциально 30-строчного… Жизнь, шашки, сапёр, морской бой, судоку…
                +8
                Пора сделать минусатор постов «XXX на JS на 30 строк» на 30 строк JS.
                  +2
                  split (в данном случае) это читерство.
                  Вообще код без 'use strict' не считается.

                  Скоро начнут постить код «Anything-you-want на javascript в одну+ строку»
                  А в титрах благодарности пакеру Дина Эдвардса
                    0
                    Ну а как без split`а еще задавать фигуки?! Получился бы 3-х мерный массив!
                    Хотя, конечно, можно было задать фигурки где-нибудь в html, но это было бы такое же читерство.
                    +10

                    Я так долго ждал линию…
                      +2
                      Довольно быстро появилась
                        0
                        Фигуры выбираются рандомом, а это значит что запросто возможна ситуация если за всю игру вообще ни разу не появится.
                          +1
                          Я уверен, в коде зашифрована проверка на необходимость линии. И не пытайтесь оспорить это.
                            0
                            Ок, даже рыпаться не стану )))
                        0
                        Тетрамино как-то неканонично поворачиваются. Плюс зависимость скорости движения от системной настройки скорости повтора символов напрягает (та же проблема была с пинг-понгом, но там вообще играть невозможно).
                          +3
                          Классно. Только есть замечание по работе кнопки Вниз. Если ее зажать, то после того как фигура упала следующая вылетает также быстро. Хочется либо задержки на один «ход» в момент когда фигура ложится, либо сброса действия кнопки Вниз для следующей фигуры, то есть для того чтобы она ускорилась нужно было бы отпустить кнопку и нажать на нее еще раз. Да, и фигуры у стены не все поворачиваются.
                            +4
                            Вот такая вот штука у меня вышла.
                            Только в 30 строк не уложились повороты фигур :(

                            <canvas id="canvas" style="background:#eeeeee" width = "200px" height="400px" ></canvas>
                            

                            var map=[], pos=5, move=0, score=0, bit=0, fig=0;
                            var canvas = document.querySelector('#canvas'),  ctx = canvas.getContext("2d");
                            function _$ (body, ret){ return eval("(function(a,b,c){"+(ret ? 'return ':'')+body+";})");}
                            _i = _$("parseInt(a)", 1);
                            range = _$("_$('for(var i='+a+'; i<='+b+'; ++i ) a(i); return 1')", 1);
                            set_color = _$("ctx.fillStyle = (['none', 'white', 'black', 'red'])[a]", 1);
                            draw_cell = _$("set_color(map[a]) && ctx.fillRect(a%10*20, _i(a/10)*20-20*3, 19, 19);");
                            can_move = _$("(b>1 || _i(a/10)==_i((a+b)/10)) && (a+b>=0) && ((a+b)<map.length) && (map[a+b]!=2)", 1);
                            bounced = _$('map.reduce(_$("a + ((b==3) && !can_move(c, "+a+")) ? 1 : 0", 1), 0)', 1);
                            cell_move = _$("can_move(a, b) && (map[a+b]=map[a]) && (map[a]=1)");
                            cell = _$("map[pos + a%4 + parseInt(a/4)*10] = (([1,15,46,78,142,204,198])[b] & (1<<(7-a))) ? 3 : 1");        
                            new_fig = _$("range(0, 7)(_$('cell(a,'+(Math.floor(Math.random()*6)+1)+')'))", 1);
                            (rng0_229 = range(0, 229))(_$("map[a] = 1"));
                            new_fig();
                            document.body.onkeydown = function(e) { 
                                (move = ([-1, 0, 1, 10])[e.keyCode-37]) && !bounced(move)
                                   && rng0_229 (_$("b = move<0 ? a : 229-a; map[b]==3 && cell_move(b, move)"));
                            }; 
                            var interval = setInterval (function () {
                                bounced(10) >0  && rng0_229 (_$("map[a]==3 && (map[a]=2)"))
                                     && range(3, 22) (_$('map.slice(a*10, a*10+10).reduce(_$("a+b", 1),0)==20 && ++score\
                                                         && range(a*10, a*10+9)(_$("map[a]=1"))\
                                                         && rng0_229 (_$("cell_move(229-a, 10)"))'))
                                     && range(20, 29) (_$("(map[a]==2) && interval && !clearInterval(interval) \
                                                      && !alert ('Game over! Score: '+score) && (interval=0) "))
                                   && new_fig();
                                rng0_229 (_$("map[229-a]==3 && a>=10 && cell_move(229-a, 10)"))
                                rng0_229 (_$("draw_cell(a)"))
                            }, 200);
                            
                              0
                              Раз уж такое дело, то вот змейка вот змейка (хотя и не идеальная, но все же).
                                +1
                                Змейка же уже была! Собственно, по моему, с нее и начался марафон мини-игр в 30 строк кода на хабре.
                                http://habrahabr.ru/post/202476/
                                  0
                                  Чтож будет еще одна :) Я как то не думал, что здесь уже целый марафон, но думаю ничего страшного.
                                    0
                                    В целом симпатично.
                                    Но она умирает при врезании в края, и при попытки движения задом (в классической попытка движения назад игнорировалась). И пару раз пропустила корм.
                                  0
                                  да и строк 100+ :) не считается
                                  0
                                  160
                                    +1
                                    270 — потом уже просто сыпятся как ненормальные
                                      +3
                                      330 ))
                                        0
                                        смог дойти до 280, потом начинается дурдом :)
                                          0
                                          А я больше 210 так и не набрал, заржавел ) В институте на Алкателе был тетрис, я в него играл часами, дошло до того, что начинал игру сразу на девятой скорости а иногда на десятой, хотя сначала казалось что на последней скорости фигур вообще не видно пока они низа не достигнут.
                                  0
                                  Пора делать хабра1k.js
                                    +5
                                    habra-9999-in-1.js
                                    0
                                    Неделя исполнения 30-ти строчных желаний. Только хотел попросить змейку она уже была, не успел заикнуться про тетрис — он тоже в строю. Даже на душе хорошо стало.
                                      0
                                      А Сокобана в 30 строк недождаться… (
                                        0
                                        > Все фигурки хранятся в переменной fs=«1111:01|01|01|01*011|110:010|011|001*...» в виде строки. Чтобы получить массив фигур — делаем split('*')
                                        Можно сэкономить на кавычках, сделав заменителем цифру:
                                        не так 'a.b.c.d'.split('.')
                                        а так 'a5b5c5d5'.split(5)
                                          0
                                          Действительно! Не знал что в split можно в качестве аргумента указывать тип number!
                                            0
                                            Указывать то можно что угодно, потом оно просто приводится к строке.
                                            Скрытый текст
                                            foo = {};
                                            bar = "0[object Object]1[object Object]2";
                                            bar.split(foo); // => ["0", "1", "2"]
                                            

                                          0
                                          А мы недавно сделали задачку по составлению алгоритма решения игры «Тетрис»

                                          Only users with full accounts can post comments. Log in, please.