первый день изучаю Lua хотел решить такую задачку: Лучник атакует Воина дальней атакой, находясь в неподвижной точке. Воин приближается к лучнику с фиксированной скоростью. Параметры лучника: ● Здоровье 600 ● Атака 10 за выстрел ● 25% вероятность x2 урона ● 40% вероятность увернуться от атаки (полностью избежав урон) Параметры воина: ● Здоровье 800 ● Атака 25 за удар ● 50% вероятность заблокировать 7 единиц получаемого урона В момент начала боя воин находится на расстоянии 60 метров от лучника. Пока воин успевает сократить дистанцию на 10 метров, лучник делает 2 попадания по воину. Скорость атаки воина в 2 раза ниже, чем у лучника.
Написал такой вот код ( делал по одному образцу, но там задача была в разы проще) :
Код
--параметры испытаний iterations = 1500000; -- итерации timeout_limit = 1000; -- число попыток, если не убили за него, то ничья distance=60; --расстояние между противниками
-- попал юнит или нет IsDamage = function(chance) local isdamage1 = false; local r = math.random(); if (r<chance) then isdamage1 = true; end return isdamage1; end -- спас бросок IsSave = function(chance1) local issave1 = false; local z = math.random(); if (z>chance1) then issave1 = true; end return issave1; end --крит IsCrit = function(chance2) local iscrit1 = false; local y = math.random(); if (y<chance2) then iscrit1 = true; end return iscrit1; end --уменьшение урона IsReduce = function(chance3) local isreduce1 = false; local f = math.random(); if (f<chance3) then iscrit1 = true; end return isreduce1; end -- [[лучник атакует
archerAttack=function() if(IsCrit(char[1].chancetocrit)) then if (IsReduce(char[2].chancetoreduceto7)) then char_B_health = char_B_health - (2 * char[1].damage - 7); else char_B_health = char_B_health - 2 * char[1].damage; end else if (IsReduce (char[2].chancetoreduceto7)) then char_B_health = char_B_health - (char[1].damage - 7); else char_B_health = char_B_health - char[1].damage; end end return archerAttack; end -- воин атакует WarriorAttack=function() if (not(IsSave(char[1].chancetosave))) then char_A_health = char_A_health - char[2].damage; end return WarriorAttack; end
-- генератор случайных чисел math.randomseed(os.time()); -- d = расстояние между противниками for d=1, distance/6 do local char_A_health = char[1].health; local char_B_health = char[2].health; local char_A_dead = false; local char_B_dead = false; archerAttack();
end
-- основной цикл for i = 1, iterations do local char_A_health = char[1].health; local char_B_health =char_B_health; local char_A_dead = false; local char_B_dead = false;
-- i2 = число попыток, если не убили за негото ничья for i2 = 1, timeout_limit do archerAttack(); archerAttack(); WarriorAttack(); if (char_A_health<=0) then char_A_dead = true; end if (char_B_health<=0) then char_B_dead = true; end if (char_A_dead or char_B_dead) then break; end end if (not(char_A_dead)) and( not(char_B_dead)) then -- считаем ничьи по таймауту отдельно timeout_count = timeout_count +1; else if (char_A_dead and char_B_dead) then -- ничьи без таймаута char_AB_wins = char_AB_wins + 1; else if (char_A_dead) then -- победил B char_B_wins = char_B_wins + 1; end if (char_B_dead) then -- победил A char_A_wins = char_A_wins + 1; end end end end print ("A wins =" .. char_A_wins .. " (" .. (100*char_A_wins/(char_A_wins+char_B_wins+char_AB_wins+timeout_count)) .. "%)"); print ("B wins =" .. char_B_wins .. " (" .. (100*char_B_wins/(char_A_wins+char_B_wins+char_AB_wins+timeout_count)) .. "%)"); print ("AB wins =" .. char_AB_wins .. " (" .. (100*char_AB_wins/(char_A_wins+char_B_wins+char_AB_wins+timeout_count)) .. "%)"); print ("timeout =" .. timeout_count .. " (" .. (100*timeout_count/(char_A_wins+char_B_wins+char_AB_wins+timeout_count)) .. "%)");
выдает ошибку lua: fight.lua:76: attempt to perform arithmetic on global 'char_B_health' (a nil value) stack traceback: fight.lua:76: in function 'archerAttack' fight.lua:96: in main chunk [C]: ?
Сообщение отредактировал EvgenShet - Среда, 14 Апреля 2021, 20:21
EvgenShet, вижу BB кодами вы умеете пользоваться, так почему для кода не применили соответствующий блок?
Что касается:
ЦитатаEvgenShet ()
lua: fight.lua:76: attempt to perform arithmetic on global 'char_B_health' (a nil value)
Вы пытаетесь обратиться к переменной, которая не была инициализирована и имеет значение nil.
Цитата
Nil - это тип, состоящий из всего одного значения, nil, основной задачей которого является отличаться от всех остальных значений. Lua использует nil для обозначения отсутствующего значения. - Роберту Иерузалимски, "Программирование на языке Lua", 2014 год, 3-е издание.
Советую посмотреть, как я понимаю, на эту строчку:
Код
local char_B_health =char_B_health;
Как я понимаю, из вашего кода, выражение там должно быть следующее:
Код
local char_B_health = char[2].health;
Сообщение отредактировал maker-rus - Четверг, 15 Апреля 2021, 10:38
Добавлено (29 Апреля 2021, 15:56) --------------------------------------------- maker-rus, не помогло, выдает ошибку, решил избавится от функций archerAttack(), WarriorAttack() прописал их в основном цикле. Теперь считает, но по моему мнению не верно. если посчитать эту задачу руками, лучник выигрывает прям совсем на тоненького. Один лишний несейв лучником или сейв воином меняет ситуацию на противоположную, а моя прога выдает 99.9 случаев победы лучника, что-то я сделал не так
Сообщение отредактировал EvgenShet - Четверг, 29 Апреля 2021, 15:57
Естественно, потому что есть еще одно такое присвоение и что важно - не одно, это касается и переменной char_A_health, я просто привел пример ошибки, а вы должны были проверить весь код на соответствие таким ошибкам по невнимательности, но вы решили пойти легким путем. Кроме этого, как я понимаю, вы не в курсе, чем отличается глобальная область видимости от локальной. Раз в цикле инициализируете переменную и потом ее пытаетесь использовать. Соответственно не слышали и про отступы (можно нажать кнопочку Tab или нажимать 4 раза пробел, это такая длинная кнопка внизу клавиатуры). Я попробовал реализовать ваш код, более - менее читаемо, вышло что-то в таком духе:
Код
--параметры испытаний iterations = 200000; -- итерации limit_step_count = 1000; -- число попыток, если не убили за него, то ничья distance = 60; --расстояние между противниками
-- структура у всех объектов ОБЯЗАНА быть одинаковой -- объекты персонажей
-- победа воина if (archer.health <= 0) then win.warrior = true; return win; end
-- победа лучника if (warrior.health <= 0) then win.archer = true; return win; end
if (limit_step == count_step) then win.nobody = true return win; end
return win; end
local count_step = 0;
for count_iterations = 0, iterations do
count_step = count_step + 1;
-- (попытка) бьет лучник if (is_attack(archer.chance_to_hit)) then warrior.health = warrior.health - (2 * archer.damage - 7); end
-- (попытка) бьет воин if (is_attack(warrior.chance_to_hit)) then -- (попытка) спас-бросок if (math.random() < warrior.chance_to_reduce) then archer.health = archer.health - (2 * warrior.damage - 7); else archer.health = archer.health - warrior.damage; end end
-- проверяем, кто победил local win = get_win(archer, warrior, count_step, limit_step_count);
-- записываем результат if (win.archer) then archer.win = archer.win + 1; warrior.lose = warrior.lose + 1;
archer, warrior = reset_player(archer, warrior); end
if (win.warrior) then warrior.win = warrior.win + 1; archer.lose = archer.lose + 1;
archer, warrior = reset_player(archer, warrior); end
if (win.nobody) then archer.nobody = archer.nobody + 1; warrior.nobody = warrior.nobody + 1;
count_step = 0; archer, warrior = reset_player(archer, warrior); end end
local function calc_win_rate(win, lose, nobody) if (win > 0) then local all_battle = win + lose + nobody; local k = win / all_battle; return math.floor(k * 100); else return 0; end end
Теперь считает, но по моему мнению не верно. если посчитать эту задачу руками, лучник выигрывает прям совсем на тоненького
Если считать по тому принципу, что написан в коде, то там ни о каком "тоненьком" и "толстеньком" не идет речи. Там безоговорочная победа воина. Так как с шансом 1, который по факту равен 100%, то есть шанс атаки = 100%, выиграет однозначно воин.
Я немного поэкспериментировал и получил следующие результаты:
maker-rus, спасибо, конечно. но я вот читаю ваш код, и насколько я могу понять он вообще не соответствует условию задачи. почему-то когда бьет лучник, воин всегда снижает урон на 7, а не в 50% случаев. когда бьет воин лучник почему-то использует 50% процентный шанс воина на снижение урона, хотя он в 40% случаев полностью игнорирует урон. Еще я не совсем понял как у вас реализована двойная скорость атаки лучника. А еще вы не реализовали то, что лучник атакует дополнительное количество раз когда они сближаются ( но я тоже не придумал как это сделать, я совсем не программист, скорее начинающий гейм дизайнер) не удивительно что при таком раскладе у вас воин вышел победителем в большинстве случаев. у меня почему-то лучник почти всегда выигрывает, что тоже не совсем похоже на правду ( а я даже не учитывал доп атаки на сближении!!) На бумаге, при расчете этой задачи в средних значениях выигрывет лучник с разрывом в одну атаку буквально. немного переделал ваш код ( не знаю как реализовать двойную скорость атаки лучника, потому написал блок с атакой лучника дважды :))
--параметры испытаний iterations = 200000; -- итерации limit_step_count = 1000; -- число попыток, если не убили за него, то ничья distance = 60; --расстояние между противниками
-- структура у всех объектов ОБЯЗАНА быть одинаковой -- объекты персонажей
-- победа воина if (archer.health <= 0) then win.warrior = true; return win; end
-- победа лучника if (warrior.health <= 0) then win.archer = true; return win; end
if (limit_step == count_step) then win.nobody = true return win; end
return win; end
local count_step = 0;
for count_iterations = 0, iterations do
count_step = count_step + 1;
-- (попытка) бьет лучник (первая атака) if (is_attack(archer.chance_to_hit)) then -- (попытка) критует лучник if (math.random() < archer.chance_to_crit) then -- (попытка) снижение урона воином if (math.random() < warrior.chance_to_reduce) then warrior.health = warrior.health - (2 * archer.damage - 7); else warrior.health = warrior.health - 2 * archer.damage; end else if (math.random() < warrior.chance_to_reduce) then warrior.health = warrior.health - (archer.damage - 7); else warrior.health = warrior.health - archer.damage; end end end -- (попытка) бьет лучник (вторая атака) if (is_attack(archer.chance_to_hit)) then if (math.random() < archer.chance_to_crit) then if (math.random() < warrior.chance_to_reduce) then warrior.health = warrior.health - (2 * archer.damage - 7); else warrior.health = warrior.health - 2 * archer.damage; end else if (math.random() < warrior.chance_to_reduce) then warrior.health = warrior.health - (archer.damage - 7); else warrior.health = warrior.health - archer.damage; end end end
-- (попытка) бьет воин if (is_attack(warrior.chance_to_hit)) then -- (попытка) спас-бросок if (math.random() < archer.chance_to_save) then archer.health = archer.health; else archer.health = archer.health - warrior.damage; end end
-- проверяем, кто победил local win = get_win(archer, warrior, count_step, limit_step_count);
-- записываем результат if (win.archer) then archer.win = archer.win + 1; warrior.lose = warrior.lose + 1;
archer, warrior = reset_player(archer, warrior); end
if (win.warrior) then warrior.win = warrior.win + 1; archer.lose = archer.lose + 1;
archer, warrior = reset_player(archer, warrior); end
if (win.nobody) then archer.nobody = archer.nobody + 1; warrior.nobody = warrior.nobody + 1;
count_step = 0; archer, warrior = reset_player(archer, warrior); end end
local function calc_win_rate(win, lose, nobody) if (win > 0) then local all_battle = win + lose + nobody; local k = win / all_battle; return math.floor(k * 100); else return 0; end end
по результатам испытаний воин выигрывает в большем числе столкновений. это потому, что лучник каждый раз не делает дополнительные 12 (2*60/10) атак, моих знаний в этом языке недостаточно чтобы это реализовать, ХЕЛП
Сообщение отредактировал EvgenShet - Вторник, 04 Мая 2021, 13:42
спасибо, конечно. но я вот читаю ваш код, и насколько я могу понять он вообще не соответствует условию задачи.
Не за что, конечно. Он не должен соответствовать условиям задачи, он является примером, как следует оформить код и каким образом его вообще писать.
ЦитатаEvgenShet ()
почему-то когда бьет лучник, воин всегда снижает урон на 7
В моем решении нет зависимости от того, кто и когда бьет. В условии моего примера лучник выполняет свои действия отдельно, воин отдельно. Ничего подобного из того, что вы написали не выполняется. В условии для атаки воина, проверяется спас-бросок, если он выполняется - урон увеличивается, не выполняется - наносится обычный урон.
ЦитатаEvgenShet ()
а не в 50% случаев. когда бьет воин лучник почему-то использует 50% процентный шанс воина на снижение урона, хотя он в 40% случаев полностью игнорирует урон
Это реализуйте сами, хотите в 50% случаев, хотите в 30%, хотите в 63%, как вам будет удобно.
ЦитатаEvgenShet ()
Еще я не совсем понял как у вас реализована двойная скорость атаки лучника
Двойной скорости лучника - нет, в условиях вообще не используется такой параметр, как скорость или дистанция.
ЦитатаEvgenShet ()
А еще вы не реализовали то, что лучник атакует дополнительное количество раз когда они сближаются ( но я тоже не придумал как это сделать, я совсем не программист, скорее начинающий гейм дизайнер) не удивительно что при таком раскладе у вас воин вышел победителем в большинстве случаев.
Я много чего не реализовал, потому что задачи такой перед собой не ставил, моя задача была не в том, что бы сделать все за вас, а предоставить базу, для улучшения и что бы другие это потом смогли прочитать, если потребуется еще помощь. Читайте внимательно:
Цитата
Я попробовал реализовать ваш код, более - менее читаемо, вышло что-то в таком духе
По поводу "не удивительно, что при таком раскладе у вас выигрывает воин". Без обид, гейм-дизайнер из вас не лучше программиста. Если у вас нет понимания, что "выиграет" воин или нет зависит от характеристик одного и другого персонажа в совокупности, а не потому что "вы не реализовали, что лучник аттакует дополнительное количество раз".
ЦитатаEvgenShet ()
у меня почему-то лучник почти всегда выигрывает, что тоже не совсем похоже на правду ( а я даже не учитывал доп атаки на сближении!!)
Потому что вы используете другой код. Да, да, так бывает. Разный код, разные характеристики, разный результат.
ЦитатаEvgenShet ()
На бумаге, при расчете этой задачи в средних значениях выигрывет лучник с разрывом в одну атаку буквально.
Мне интересно, каким образом на бумаге вы рассчитываете псевдослучайные числа? Есть большие сомнения в правильности ваших вычислений. Либо вы, одновременно, кроме того, что дизайнер, еще и Нострадамус.
ЦитатаEvgenShet ()
немного переделал ваш код ( не знаю как реализовать двойную скорость атаки лучника, потому написал блок с атакой лучника дважды :))
И снова - здарова. Я правильно понимаю, что вы ничему не учитесь? Посмотрите на мой код, а потом на свой. Чем они отличаются?
ЦитатаEvgenShet ()
по результатам испытаний воин выигрывает в большем числе столкновений. это потому, что лучник каждый раз не делает дополнительные 12 (2*60/10) атак, моих знаний в этом языке недостаточно чтобы это реализовать, ХЕЛП
Ваших знаний не только в скриптовом языке маловато, к сожалению. Распишите корректно, что и как должно у вас выполняться. Потому что на данный момент я вижу следующее в ваших словах: "мгм... лучник живет на дереве и он должен ускоряться на 50% процентов, а воин не должен ускоряться, он должен махать топором, поэтому когда он вращается - лучник танцует, а это значит, что дерево должно гнуться, из-за этого Король Империи Гномов объявил войну великанам."
maker-rus, А вот оно что, это пример отличный от моего, окей. Что я не могу сейчас понять: По моим условиям до реализации цикла ( два удара лучника, удар воина, повторить до тех пор пока кто-то не помрет) должны быть несколько атак лучника. Как мне записать эти атаки чтобы они выполнялись в начале схватки каждый из n количества боев, но при этом не повторялись каждый шаг боя.
Как мне записать эти атаки чтобы они выполнялись в начале схватки каждый из n количества боев, но при этом не повторялись каждый шаг боя.
Для начала необходимо выстроить конкретную последовательность действий, что конкретно происходит, после какого конкретно шага это происходит, что происходит в момент атаки, как происходит атака, кто атакует, какой урон наносит, от чего зависит ударит-ли лучник или воин, или не ударит. Если ударит - нужно ли добавлять к урону какой-то эффект? Если нужно, то какой, каким образом он влияет на атакующего, что конкретно он добавляет, вычитает, складывает, умножает, делит. И так далее, каждый шаг. Как сможете выстроить эти шаги - напишите их тут и продолжим уже составлять блок-схему алгоритма, а потом из него переносить в реальный код.