Skip to main content

урок 1

Совсем скоро мы начнем с вами писать свою игру в roblox. В нем все программирование будет на языке Luau - диалекте Lua с постепенной типизацией. Поэтому сегондя наша задача - вспомнить как вообще в lua писать. Откроем онлайн инетрпертатор, например https://play.luau.org/

Именная конвенция

Поскольку очень часто люди пишут один проект вместе, есть определенные договоренности. В том числе они зависят от языка. В роблоке принято писать :

переменные, функции классовые поля - camelCase

константы - LOUD_SNAKE_CASE

API роблокса, названия классов и энумераторов - PascalCase

Переменные

В luau есть следующие типы переменных:

  • nil - неуказаное значение, единственное, приводящееся к false (0 ~=false)
  • boolean ∊ {true;false}
  • number == float
  • string - строка текста произвольной длины
  • function - ссылка на функцию
  • table - ассоциативный массив (помесь list и dict)

Называть переменные можно любыми названиями, кроме начинающихся с цифр и зарезервированных слов.

Есть возможность параллельного присваивания

local x, y = 90, 'fff'  -- x= 90, y = 'fff'
x, y = y, x             -- x= 'fff', y = 90

Области видимости

По умолчанию у пременной область видимости - global.

Пожалуйста, делайте их локальными и const, если это применимо. Luau гораздо быстрее работает с локальными переменными.

local isGameActive = true          -- boolean
local playerScore = 150            -- number
local playerName = "Alex"          -- string
local randomArray = { 8, "a19", nil, false, {true, isGameActive} } -- table with assumed index of 1,2,3...
local playerStats = {              -- table with custom index
    health = 100,
    mana = 50
}

Арифметические операции

помимо базовых +-*/ есть:

% - остаток от деления

^ - степень

IF

if <условие> then

<действия>

else

<действия2>

end

Чуть больше о массивах

массивы нумеруются с 1. Соответвенно индекс последнего элемента - мощность множества +1

Чтобы найти мощность (длину) массива , испольуется #name

local randomArray = { 8, "a19", nil, false, {true, 1} }
print(#randomArray) -- выведется 5

Для индексации внутри массива используется []

local randomArray = { 8, "a19", nil, false, {true, 1} }
print( randomArray[2] ) 
-- вывод 'a19'

Чтобы добавить значение в массив:

local randomArray = { 8, "a19", nil, false, {true, 1} }
randomArray[ #randomArray+1 ] = 'это последнее значение'

table.insert(randomArray , 2 , 'хаха я вставил это во вторую позицию')

-- randomArray == {
  ["1"] = 8,
  ["2"] = "хаха я вставил это во вторую позицию",
  ["3"] = "a19",
  ["5"] = false,
  ["6"] = {true,1},
  ["7"] = "это последнее значение",
}

Учтите, что поскольку для Lua таблица - просто словарь, то сохранять значение nil она не будет, просто пропустив его.
local randomArray = { 8, "a19", nil, false, {true, 1} }
randomArray == {1 = 8, 
                2 = 'a19',
                --третьего индекса просто нет, поскольку там nil
                4 = false,
                5 = { 1 = true , 2 = 1}
                }

Циклы for

Цикл for берет как рабочую переменную либо созданную,

for i = startValue , endValue , stepValue do
    --действия
    end

либо уже существующую таблицу, тогда на вход дается два значения index , value :

local randomArray = { 8, "a19", nil, false, {true, 1} }
for index , value in randomArray do
    print(index , value)
end

--[[выведется 
1 8 
2 a19
4 false
5 { true, 1}
]]--

Принято неиспольлзуемую переменную называть _

local randomArray = { 8, "a19", nil, false, {true, 1} }

for _,v in randomArray do
    print(v)
end


Чаще всего для перебора в словарях используется pairs(dict), а в списках - ipairs(array)

Итерацию цикла можно закончить досрочно с помощью continue, а из цикла целиком можно выйти с помощью break

Задача №1

Создать список всех чисел [1,100] , делящихся на 7

Можно сделать это двумя способами. Дайте ребятам время подумать и не наказывайте за использование чита в виде for:

способ #1 - трушный, через проверку каждого числа

local divBy7={}
for candidate = 1,100 do
    if candidate %7 ==0 then 
        divBy7[#divBy7+1] = candidate
    end
end

спобос #2 - читовый

local divBy7={}
for candidate = 7,100,7 do
    divBy7[#divBy7+1] = candidate
end

Задача №2

Создать список всех простых чисел в промеждутке [2,100]

1 - не простое число (согласно Математическая энциклопедия (в 5 томах) и Arguments for and against the primality of 1

Пример решения (без какой либо оптимизации):

local primes = {}
for candidate = 2 , 100 do 
    local isPrime = true
    for possibleDivisor = 2 , candidate-1 do 
        if candidate % possibleDivisor == 0 then 
            isPrime = false
            break
        end
    end
    if isPrime then
        primes[#primes+1] = candidate
    end
end

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

local primes = {2}
for candidate = 3 , 100, 2  do 
    local isPrime = true
    for possibleDivisor = 2 , math.round(candidate/2) do 
        if candidate % possibleDivisor == 0 then 
            isPrime = false
            break
        end
    end
    if isPrime then
        primes[#primes+1] = candidate
    end
end

Функции

Для создания функции:

local function name( --[[inputVars]]-- )
    --operations
    опционально return <возвращаемое значение>
end

Например, функция, которая прибавляет к числу 1

local randomArray = { 8, "a19", nil, false, {true, 1} }


local 

Задача №3

Занулить массив. Массив дан. После результата работы функции все значения в нем должны быть 'ДАННЫЕ УДАЛЕНЫ'

Учтите, что при использовании цикла for, как и всегда, передается копия массива,а не он сам. Для изменения массива используйте индексацию в него

-- не сработает

local randomArray = { 8, "a19", nil, false, {true, 1} }

local function delete( array )
    for _,v in array do
        v = 0
    end
end


-- сработает 

local randomArray = { 8, "a19", nil, false, {true, 1} }

local function delete( array )
    for i,_ in array do
        randomArray[i] = 0
    end
end

Задача №4

Попробуем решить какоe-нибудь сложное уравнение простым подбором. Для этого определим сначала, с какой точностью ответ нам подойдет, т.е. погрешность.

Затем просто будем проверять числа, пока не найдем нужное.

Для примера, возьмите уравнение 2*n^3 + 6*n^2+7*n+2 = 0

Чтобы найти, насколько мы близки к ответу, берем модуль результата и сравниваем с допуском (привет, предел по Коши)

local function solver(range)
    local answers = {}
    for  n = -1000 , 1000 , 0.0001 do
        if math.abs(2*n^3 + 6*n^2+7*n+2)