понедельник, 8 августа 2016 г.

Всё, наскладывались оригами

Три дня прошли, контест закончен. Всё круто, сейчас надо отдохнуть. :)

пятница, 5 августа 2016 г.

Лидерборд апдейт

Сейчас 8:48. Какие-то бомжи на первом месте в лидерборде.


четверг, 4 августа 2016 г.

Продолжаем наблюдать за твитами ICFPC-2016

Смотрим, что нам пришло:
->>>+++++>>+>+>> +>++>+>+[+++[>++ ++++++#<->>+ >[-]>.-#[>>>>>>[ +<]>--#]#>--.->- --..>#>->#.->--> ++++.+++>.[-]<<< <[.<]>[>]<[.<]<<.
Кто-то комментирует, говорит, похоже на оригами. В общем, это программа на языке Brainfuck, которая выводит следующее:
 Hello, fold/unfold!
В общем, орги продолжают намекать.

ICFPC-2016, меньше 12 часов до старта

В общем, осталось времени до старта совсем чуть-чуть, расчехляемся потихоньку. Ну и заодно смотрим, что нам там пишут организаторы. А пишут следующее (последние три записи):

1.upto(99){|_|puts'FizzBuzz '[o=_**4%-15,o+13]||_}
Это на руби. Выводит следующую последовательность:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
FizzBuzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
FizzBuzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
=> 1
 Смысл в том, что выводятся числа от 1 до 99 и там, где число делится на 3, пишут Fizz, где на 5, пишут Buzz, а где и на 3, и на 5 - FizzBuzz. В общем, такая шляпа широко используется в качестве тестового задания и даже приводят почему именно оно так хорошо раскрывает потенциал программиста. Правда, я не понял. :) Точнее, задача позволит отсеить откровенного непрограммиста.

Так же это детская игра считалочка, когда детки садятся в круг и считают. По тем же правилам, что выше описано. Кто ошибся, вылетает. Ну и в конце останется только один. :)

Далее что мы имеем? Имеем некий запрос - Закидывание забутонами. Забутон это такой стул без ног. Которым кидают в сумоиста, который по рангу сильнее, но проиграл. Такие вот японские забавы. У моря живут, помидоров и яиц дефицит.

И третий пост - "Check or Fold?" Термины check и fold относятся к покеру. Check - пропуск хода, fold - сброс карт. 

Итого в конце останется только один! Победитель. Вероятно, всё будет в форме игры. То есть решения будут соревноваться друг с другом. Без рейтинговой таблицы. Возможно, что-то будет похожим на карты. И проигравшего закидают тухлыми яйцами. Простите, забутонами. В общем, сидим, ждём.

И да, самый главый момент. В этом году наша команда выступает на хаскеле. Я его всю неделю учил. Не скажу, что понравился, но и не скажу, что прям сильно не понравился. Ясно, что в ICFPC и иже с  ним далеко не язык определяет победу. Так что начало в 03 утра по Мск. Ждём. :)

среда, 27 июля 2016 г.

Не стартует OpenVPN на Debian 8 (jessie)

В общем, казалось бы, всё сделал хорошо, конфиги переписал, ключи положил. Перезапускаю сервис openvpn и тишина. Интерфейсы не создаются, в логах только запись о перезапуске...
Но я то уже опытный, я помню, что в Debian 8 по сравнению с Debian 7 может быть всё иначе. В общем, проблема заключается в том, что по умолчанию OpenVPN не производит автостарт конфигов в папке. Вместо этого там крутой такой механизм через systemd, чтобы иметь возможность запускать несколько разных соединений. Хорошо и функционально, не спорю. Но слегонца непрактично, особенно учитывая предыдущий совершенно другой опыт.
В общем, лечится просто (если мы не хотим заморачиваться с тонкой настройкой) - в файле /etc/default/openvpn находим строчку:
#AUTOSTART="all"
И раскомментируем её. Ну а далее стандартные шаманства:
systemctl daemon-reload 
service openvpn restart
 И всё. В общем, памятка. Надеюсь, не пригодится. :)

 

вторник, 26 июля 2016 г.

ICFPC-2016, вот он и пришёл

Причём пришёл совершенно нежданно и негаданно. Всё смотрел, ждал и ждал, а тут и бац, в скайпе вылавливают и сообщают. В общем, страница контеста. А вот ещё и их twitter. В общем, пока непонятно и никаких подсказок не увидел. Буду мониторить. А, да, начало то 5 августа в 03:00 по MSK. Это 00:00 по UTC. В общем, вот так вот.

пятница, 22 апреля 2016 г.

Тяжести разработки под Android и HTML5

Наконец-то опубликовали нашу простенькую игру Пузыри в гугл плей - (официальный пресс-релиз). Немножко под катом - игра основана на технологии HTML5, а в Javascript компилируется Clojurescript. Причём, использование ClojureScript открывает широкие возможности по написанию кода и отлаживанию его. Кстати, всё это работает и в браузере. В целом, в Android используется тот же браузер, но есть нюансы. Первый - этот браузер (системный WebView) везде разный и на что-то положиться особо нельзя. Да и более или менее приличный идёт только начиная с Android 5.0. Чтобы выйти из этой ситуации, в приложении тащим Chromium, который весит уже поболее. Хотя, в наше время это не так критично, но всё же. С другой стороны, я посмотрел, все так делают. Да и к этому нужно было прийти. Есть проекты типа cordova, которые бы позволили опубликовать это легко и удобно, но и там свои нюансы. Например с фуллскрином и сплешскрином. Из нормальных - coconjs, но он весь такой из себя облачный, что вносит свои неудобства. Ну и главный препон - это технологическое развитие. Я имею в виду всякие WebGL, с которыми всё быстре и которое нормально будет работоать с 5.0 Android. Хотя, терпимо работает и на 4.4. В общем, опубликовали, в итоге. :)


пятница, 29 января 2016 г.

Reagent - вся модность ReactJS на ClojureScript

Как описывают создатели ReactJS, пользовательский интерфейс становится всё сложнее и сложнее, и тем он сложнее, чем он комплекснее. А интерфейсы усложняются, пытаются в браузере сделать всё. В целом, может, это и неплохо, но потребность в чём-то просто есть.Вообще, про реактивное программирование говорили ещё давно, но вот сейчас оно пошло в широкие массы.

ClojureScript тоже решил не оставаться в стороне и какие-то ребята запили обёртку под это дело. В целом, там же Getting Started и ещё есть куча различных туториалов, где всё подробно расписано. Суть сводится к тому, что есть некоторое состояние приложения (или несколько их), которое инкапсулируется в реактивном атоме (reagent.core/atom), и есть компоненты, которые суть есть кусок DOM, изменяющийся в зависимости от состояния. Собственно, это автоматическое изменение и есть работа ReactJS. Звучит просто? Но, в целом, так оно и есть. Рассмотрим чуточку подробнее на примере игры Memory Game, исходники которого можно глянуть тут.

(def game (r/atom {}))
Который на старте игры инициализируется  следующим:
(-> game'
  (assoc-in [:level] level)
  (assoc-in [:state-changed] true)
  (assoc-in [:w] w)
  (assoc-in [:h] h)
  (assoc-in [:can-open] true)
  (assoc-in [:board] board)
  (assoc-in [:opened] [])
  (assoc-in [:opened-count] 0)
  (assoc-in [:score] 0)
  (assoc-in [:state] :playing))
Собственно, это всё, что хранится в состоянии игры. Ну, а сама инициализация рендеринга:

(r/render-component [game-component] (.getElementById js/document "app"))
Далее, сам компонент game-component является обычной функцией ClojureScript и собирает в себя остальные компоненты:

(defn game-component []
  (let [cur-game @game]
    [:div.container.container-table
     [:div.row
      [:div.col-md-3.col-md-offset-2
       [:div "Restart with level:"]
       [:button.btn.btn-xs.btn-default
        {:type "button"
         :on-click #(start :easy)}
        "Easy"]
       [:button.btn.btn-xs.btn-default
        {:type "button"
         :on-click #(start :normal)}
        "Normal"]
       [:button.btn.btn-xs.btn-default
        {:type "button"
         :on-click #(start :hard)}
        "Hard"]
       [score-component (:score cur-game)]
       [game-state-component (:state cur-game) (:score cur-game)]
       [:p "Rules: " "Open two matched cards and they will stay opened. "
        "Otherwise it will be closed, but you memorize it's locations."]
       [:p "Author: " [:a {:href "https://bitbucket.org/turtle_bazon/"} "Azamat S. Kalimoulline"]]
       [:p [:a {:href "https://bitbucket.org/turtle_bazon/cljs-games/src/"} "sources"]]]
      [board-component]]]))
При этом тут используется расширенный синтаксис квадратных скобочек, который, помимо прочего, означает, что тут необходимо вызвать функцию компонента. При этом не просто вызывать, а как-то что-то сделать и пометить там у себя, чтобы эта функция вызывалась только при изменении той ветки стейта, на основе которой он рендерится. Для этого функция должна принимать аругменты, которые как раз будут веткой (-ами) состояния.

Отдельное внимание стоит уделить компоненту board-component, который рендерит доску NxM размера. По сути, доска состоит из строк, а строки состоят из ячеек. Так вот, получается, что внутри board-component есть повторяющиеся row-component, внутри которых повторяющиеся card-component. Чтобы ReactJS смог разобраться с этим, чтобы не перерендеривать всю строку целиком, ему нужно помочь, задав некоторый идентификатор с помощью "^{:key id}":

(defn row-component [row]
  [:div.board-row
   (for [[id card] row]
     ^{:key id} [card-component id card])])

(defn board-component []
  (let [cur-game @game
        w (:w cur-game)
        h (:h cur-game)
        cards-array (partition
                     w
                     (map (fn [id card]
                            [id card])
                          (for [row (range 0 h)
                                col (range 0 w)]
                            (+ (* w row) col))
                          (:board cur-game)))]
    [:div.board.col-md-5
     (for [[row row-index] (map vector cards-array (range 0 h))]
       ^{:key (str "r" row-index)}
       [row-component row])]))
Ну а вообще, получается вполне симпатично, весь пользовательский интерфейс отрисовывается на основе состояние и изменением состояния контролируется пользовательский интерфейс. Всё чисто и понятно, если нас не подведут Reagent и ReactJS. То есть там происходит какая-то их магия, но пусть.

Итого - очень даже интересная технология, которая позволяет избавиться от жёсткого связывания модели и логики отображения. Из минусов можно отметить, что всё делается в hiccup стиле, что вынуждает верстальщика учить Clojure или, наоборот, программиста учить вёрстку. Что, по моему личному мнению, не очень хорошо. Но как раз для решения таких проблем существует проект kio, который позволяет выделить верстальщика отдельно и радоваться жизни.

Ну а подводя полный итог можно сказать, что уж если мы решили делать интерфейс в вебе, то нам, скорее всего, понадобится использовать что-то подобное, в противном случае он рискует значительно быстрее превратиться в нагромождение непонятной лапши.


четверг, 21 января 2016 г.

ClojureScript и Phaser.io

Недавно я писал, что так и не смог подружить ClojureScript и Phaser, и что там возникала ошибка, чего не было в Parenscript. Тогда времени было мало, сейчас же решили с virvar'ом основательно разобраться. Итого, проблему на github я закрыл. Причина же была проста. В первом примере я вообще забыл *platforms* включить физическое тело, из-за чего дальнейшие операции с ним были недоступны, а во втором варианте при использовании *platforms* не был произведён deref во время операции включения физического тела. Итого два подхода вывалились с одной ошибкой, что не позволило использовать ClojureScript на LispJam. Грустно, но се ля ви. Итого реализовал туториал на ClojureScript с использованием библиотеки phzr. Итоговые изыскания - тут.

суббота, 16 января 2016 г.

Коварные зомби съели мою корову! или история одного Lisp Game Jam

Кто-то режет салат, кто-то его ест, все поздравляют друг друга с новым годом, а мы упоролись. А упоролись такой забавной штукой как Lisp Game Jam 2016. Чтой та я решил? Да просто как-то ещё в конце декабря прошлого года в наш уютный и ламповый чатик товарищ c1tr00z запостил ссылку на предстоящий джем. Что такое джем я тогда не знал, да и сейчас не особо понимаю, но смысл описывался в том, что нужно создать игру на каком-нибудь диалекте лиспа за 7 дней. Позже дедлайн продлили ещё на три дня, но это всё вписывалось на предстоящие каникулы. В общем, подбил я c1tr00z'а, а ещё и virvar'а и понеслась.

Далее идёт портянка для любителей читать, для остальных предлагаю ознакомиться с официальным пресс-релизом группы, где кратенько об этом же, или играть онлайн, либо же посмотреть исходный код.

Phaser

Таки сначала предстояло определиться с тем, что же использовать? Можно было использовать тру CL и cl-sdl в нём, можно было заюзать какие-нибудь биндинги к Unity3d или напилить их, но всё это было не то. Хотелось простоты дистрибутинга, а это нам давал только web. А web это яваскрипт, значит, нам нужен был яваскрипт движок. Не помню что и как искал, но нашёлся turbulenz. Первая проблема возникла после того, как я решил посмотреть что он умеет и что на нём сделано, нашёл игру Monster Force... В общем, через два дня изучения возможностей движка на примере данной игры :), скачал SDK, офигел и закрыл. Какие-то редакторы, что-то компилить и т.д. В общем, даже разбираться не стал. Начал смотреть что есть. Из всего многообразия, включая вские Panda.js и Crafty, c1tr00z таки подсказал, что есть ещё Phaser, что-то ещё и что-то ещё. Так как он был на первом месте, пошёл смотреть его. Был тутор, как создать первую игру, были другие туторы игор. Далее я делал следующее - я читал тутор phaser'а и смотрел, как там написано на яваскрипте, потом я читал доку на parenscript, чтобы написать так, чтобы он перевёл в тот яваскрипт, что на туторе, далее, собственно, это делал сам parenscipt, браузеру приходил красивый явскрипт, который, можно подумать, написал человек. В общем, квес с тутором был пройден, я его продемонстрировал и решили на phaser'е и остановиться.

Parenscript

Изначально, раз CL, то первым выходи parenscript. А это транслятор. С подмножества CL в яваскрипт. Из плюсов - неплохо так это делает, всё читается и дебажится из браузера. Минусы смутили больше, чем обрадовали плюсы - это просто транслятор, нет репла, нет среды разработки, не выработы правила создания, плагин к asdf для компилирования parenscript, который называется paren-files, имел коммит 6 (!) лет назад, с текущим ASDF3 не работает. В общем, ничего нет для parenscript. Сделали и забыли. Эта ситуация сильно удручила и я захотел реализовать это на чём-то современном, например, GWT ClojureScript. Нашёл библиотеку для clojurescript phzr и, засучив рукава, принялся делать ещё один туториал. Но почему-то body или что-то там было undefined, где оно таковым не должно было быть, и решил, что нужно использовать тру clojurescript без всяких обёрток НО ситуация повторилась один в один. Есть issue на гитхабе, где я описал свои злоключения, но ответа до сих пор нет. Что-то другое искать времени уже не было, поэтому решил, что нужно допинать parenscript, а в коде догнаться макросами. В общем, приступили на parenscript. Хорошо это или плохо пока не знаю, но конечный результат есть.

Сам джем

Как и планировалось, c1tr00z занялся исключительно графикой и основной частью гейм дизайна. Решили писать про ковбоя, который будет убивать пришельцев. Как я понял, после попытки прорисовать пришельцев, получились зомби, ну да ладно. Собственно, это была довольно нудная работа по припиливанию новых возможностей. Опять же, имя на руках паренскрипт, у нас был всего лишь яваскрипт со скобочками, что удручало. Тем не менее, использование макросов очень даже помогло. В целом, и движок phaser оказался относительно вменяемым. Дело пошло бодрее, когда подключился virvar, который думал, что 10-го джем только начинается. :) Ну а далее начал страдать дизайн кода, на который уже особо внимания не осталось в виду надвигающегося дедлайна. В общем, кое-как доделали и засабмитили под утро.

Итоги

До этого я ни в каких джемах не участвовал. Максимум, чем развлекался - это ICFPC. Это вообще разные задачи и разный экспириенс. Что же я усвоил и приобрёл?

  • главный итог в том, что игру мы эту таки сделали. Не забросили посередине, а вполне ко сроку уложились и это, считаю, огромный плюс в копилку экспы;
  • гейм индустрия очень интересна и манит кучей всего и тулов есть кучу разных. Изначально искал что-то простое, что подключил, написал, оно и готов. Вот Phaser в этом плане себя оправдал на все 100%;
  • parenscript это всё же яваскрипт со скобочками, ведь вполне присутствую проблемы с this внутри foreach и т.п. Вообще на этом джеме ояваскриптились. Но писать в скобочках всё равно приятнее. :) Но если сравнить ClojureScript и Parenscript, то, несомненно, победителем выходит ClojureScript. Ведь это действительно лисп со всеми его возможностями;
  • hunchentoot что-то не захотел работать у c1tr00z'а под виндой, что тоже насторожило;
  • близость дедлайна может превратить любой код в страшное месиво. :)
Вот. А в остальном было весело. Считаю, что каникулы прошли с пользой. Буду ли участвовать ещё в джеме? Возможно. ;)