Перейти к публикации
Форум - ComputerCraft
  • записей
    9
  • комментариев
    116
  • просмотров
    80 860

Поговорим о Луне! #0. Угадываем числа.

Totoro

1 664 просмотра

На днях я рассказывал об интересном языке для OpenComputers (и не только).
MoonScript

 

Но одно дело - прочитать об языке где-то. А совсем другое - попробовать язык самому.
Именно этим я и предлагаю заняться.

 

Для разогрева, начнем с чего-нибудь несложного. Например "Угадай число".
Думаю все знают эту игру. Компьютер загадывает число, мы пытаемся угадать. На каждую нашу попытку, компьютер злорадно сообщает - "больше!", "меньше!" или "у вас закончились попытки!" и "вы проиграли!".
Немного модифицируем исходную идею, и перенесем ее на 2d поле. Просто, чтобы не было скучно.

 

ТЗ
Что нам потребуется?
1) Отрисовать сетку
Тут мы просто возьмем текущий размер дисплея, и разметим его на клеточки.
2) Загадать число
3) Слушать команды пользователя
Юзер будет тыкать на клеточки. Нам надо будет слушать эвент touch.
4) Обновлять игровое поле в ответ
Собственно после тыка, будем открывать клетку. Если это не та клетка - рисовать на ней стрелочку. Если та - рисовать победный баннер. Если закончились ходы - рисовать что-нибудь обидное.

 


За дело
Первым делом надо подключить все, что мы будем использовать.
В Lua обычно мы при помощи команды require пишем все в локальные переменные.
В MoonScript все переменные по дефолту локальны. Поэтому использовать ключевое слово local нет необходимости.
Для подключения же, используется ключевое слово import:

 

import  getResolution  setForeground  setBackground  set  fill  from require('component').gpuimport pull from require 'event'import ceil, random from mathimport rep from string


Мы вытащили из нужных библиотек нужные функции. Ничего лишнего.

 

Теперь объявим переменные, которые будут использоваться в коде.

- Размеры экранаwidth, height = getResolution()width /= 2    -- потому что по горизонтали наши клетки займут 2 символаheight -= 1   -- потому что внизу будет статус-- Цветаwhite = 0xFFFFFFblack = 0x000000gray  = 0x222222green = 0x00BB33yellow = 0xFFC04Cred = 0xFF0000pink = 0xFF0074violet = 0xD600FFblue = 0x4E5AFFcyan = 0x4ED7FFteal = 0x00CC99-- Заготовка для сетки - один ряд клетокgrid_line = rep("▒▒  ", ceil(width / 2))-- Наша цельtarget = { x: 0, y: 0 }-- Количество попытокmaxAttemts = ceil(width * height / 150)    -- 150 - магический коэффициент сложности, больше - сложнее, меньше - легчеattempts = maxAttemts


Тут тоже присутствует несколько новых фич MoonScript.
Во-первых - это сдвоенные операции. Конструкции a /= b или a -= b означают тоже самое, что a = a / b и a = a - b.
Во-вторых это новый синтаксис создания таблиц. Названия полей и их значения отделены двоеточиями. (Такое обозначение будет знакомо тем, кто владеет JavaScript).

 


Для реализации геймплея и отрисовки всякой всячины, потребуется определить несколько функций.
Тут мы столкнемся еще с несколькими новшествами, по сравнению с Луа.
Первое, в MoonScript нету ключевого слова end. Блоки кода обозначаются отступом разной величины.
Так что вам придется тщательно следить за тем, на каком уровне вы пишете команды. (Это чертовски полезно, и вырабатывает красивый стиль написания кода =), а не эти кошмарные простыни, где нельзя разобрать начал и хвостов.)
Второе, функции объявляются конструкцией вида (a, b, c) -> .... Тут слева - набор аргументов, потом стрелочка - разделитель и блок кода, который собственно является телом функции.

-- Очищаем экранclear = () ->  setForeground white  setBackground black  fill 1, 1, width * 2, height + 1, ' '-- Рисуем сеткуgrid = ->  setForeground gray  setBackground black  for y = 1, height    set (if y % 2 == 0 then 1 else 3), y, grid_line


Пустой набор аргументов можно опустить, как в функции grid.
Кроме того, как несложно заметить, MoonScript позволяет вызывать функции, не используя скобочки.

 

Продолжим.

-- Открываем одну клеткуsign = (x, y) ->  if x == target.x and y == target.y then black, white, "[]"  elseif x == target.x and y < target.y then white, green, "▼▼"   -- по неведомой мне причине, стрелки вниз в новом шрифте ОС 1.6 нету =)  elseif x == target.x and y > target.y then white, violet, "↑↑"  elseif x < target.x and y < target.y then white, teal, "↘↘"  elseif x < target.x and y == target.y then white, cyan, "→→"  elseif x < target.x and y > target.y then white, blue, "↗↗"  elseif x > target.x and y < target.y then white, yellow, "↙↙"  elseif x > target.x and y == target.y then white, red, "←←"  elseif x > target.x and y > target.y then white, pink, "↖↖"cell = (x, y) ->  fore, back, text = sign x, y  setForeground fore  setBackground back  set x * 2 - 1, y, text


Здесь функция sign сконструирована так, чтобы отдавать три переменных разом.
Следует заметить, что в MoonScript можно не пользоваться оператором return.
Функция автоматически вернет значение последнего оператора в теле.
Кроме функций, значения умеют возвращать и условия. Поэтому в данном случае, функция возвращает значение условия, а условие возвращает три значения из той ветки, которая выполнится.

 

Функция cell просто берет эти значения и отрисовывает в нужном месте клетку.

 

Далее.

-- Рисуем статусstatus = (state) ->  setForeground white  setBackground black  fill 1, height + 1, width * 2, height + 1, ' '  set 2, height + 1, "[Угадай, где клад!]"  switch state    when 'win'      setForeground green      set 24, height + 1, "Вы победили!"    when 'lose'      setForeground red      set 24, height + 1, "Вы проиграли!"    else      set 24, height + 1, "Попыток осталось: #{attempts}"  set width * 2 - 10, height + 1, "[R] [Q]"


Здесь тоже используются две новые конструкции.
Первая - это switch. Наверняка многие уже знакомы с ним. По сути, это просто удобный вариант длинных условий, со множеством elseif. Свитч получает значение, а потом сравнивает с ним все ветки when. Какая совпадет - та и выполнится.

 

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

 

Последние приготовления:

-- Генерируем цельsetTarget = ->  target = { x: random(1, width), y: random(1, height) }-- Инициализируем игруnewGame = ->  attempts = maxAttemts  setTarget!  clear!  grid!  status!


Функция newGame использует специальный синтаксис для вызова функции, которой не нужны аргументы.
Вместо того, чтобы писать setTarget(), MoonScript советует использовать восклицательный знак. setTarget!.
Это довольно весело смотрится в коде. =)

 


Ну чтож, все готово.
Давайте соберем все написанное, и запилим немного игровой логики!

 

-- Поехали!newGame!while true  -- Ждем события  event, _, x, y = pull!  -- Обрабатываем его  switch event    when 'touch'   -- Если был клик      -- Открываем клетку, если остались попытки      if attempts > 0        x = ceil(x / 2)        cell x, y        attempts -= 1        -- Обновляем инфу        if x == target.x and y == target.y          attempts = 0          status('win')        elseif attempts == 0          status('lose')        else          status!    when 'key_down'      switch x        when 113   -- Q: выход из игры          break        when 114   -- R: перезапуск          newGame!clear!


Вуаля! Оно работает. И даже можно поиграть. И даже победить =)

 


4s8lawq.png

 


Круто, правда?
Не надо делать такое выражение лица, я знаю что на самом деле, вы со мной согласны. =)
А вы, да-да, вы! - на задних рядах, хватит кидаться тапками!

 


Полный код игрушки доступен тут:
http://pastebin.com/M0sxk1QH

 

Enjoy!

  • Like 11


6 комментариев


Рекомендованные комментарии

Кидаю тапок в небо. До Луны долетит?..

В общем, спешу сообщить, что круто. В блокнотик пометку поставил теперь, чтобы посмотрел подробнее в мануалы по мункрипту.

Поделиться комментарием


Ссылка на комментарий

Довольно интересная вещица... посмотрим, если будет время, буду обучаться потихоньку.

Импорт нужных функций - экономия.

Свитчи - тоже. И вообще мунскрипт для меня выглядит опрятно.

Пять за все-просто-быстро-и-понятно :)

Поделиться комментарием


Ссылка на комментарий

Рад, что получилось понятно. Как всегда пишу по ночам, в состоянии легкого красноглазия, поэтому сам оценить не могу.

 

P.S. За тапок спасибо, долетел, если подгоните второй - будет здорово. =)

Поделиться комментарием


Ссылка на комментарий

...

P.S. За тапок спасибо, долетел, если подгоните второй - будет здорово. =)

  Прикольненько. Осталось добавить человечка, который будет шагать по лабиринту(притом открывая его) и ориентироваться по стрелкам(которые ему будут попадаться на пути, время от времени), вычисляя приблизительное местонахождение клада.  Как-то так. :)

  Ссыль утянул себе в "нору". Может посмотрю на досуге.

 

P.S.   И будут у тебя - два левых тапка. =)

Поделиться комментарием


Ссылка на комментарий

*пустил слезу радости*
Классная статья, молодец что продвигаешь 

 

 

Думал сначала прикрутить with, но понял, что ничего не меняется, хотя эту конструкцию уверен можно до двух строк уменьшить.

sign = (x, y) ->
  with target
    return if x == .x and y == .y then black, white, "[]"
    elseif    x == .x and y <  .y then white, green, "▼▼"
    elseif    x == .x and y >  .y then white, violet,"↑↑"
    elseif    x <  .x and y <  .y then white, teal,  "↘↘"
    elseif    x <  .x and y == .y then white, cyan,  "→→"
    elseif    x <  .x and y >  .y then white, blue,  "↗↗"
    elseif    x >  .x and y <  .y then white, yellow,"↙↙"
    elseif    x >  .x and y == .y then white, red,   "←←"
    elseif    x >  .x and y >  .y then white, pink,  "↖↖"

Поделиться комментарием


Ссылка на комментарий

Думал сначала прикрутить with, но понял, что ничего не меняется, хотя эту конструкцию уверен можно до двух строк уменьшить.

 

Наверняка. =)

Но я решил не мудрить в рамках статьи.

Поделиться комментарием


Ссылка на комментарий

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас
×