Четверг, 28 Ноября 2024, 22:13

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
ошибка в LUA
EvgenShetДата: Среда, 14 Апреля 2021, 20:17 | Сообщение # 1
был не раз
Сейчас нет на сайте
первый день изучаю Lua хотел решить такую задачку:
Лучник атакует Воина дальней атакой, находясь в неподвижной точке. Воин
приближается к лучнику с фиксированной скоростью.
Параметры лучника:
● Здоровье 600
● Атака 10 за выстрел
● 25% вероятность x2 урона
● 40% вероятность увернуться от атаки (полностью избежав урон)
Параметры воина:
● Здоровье 800
● Атака 25 за удар
● 50% вероятность заблокировать 7 единиц получаемого урона
В момент начала боя воин находится на расстоянии 60 метров от лучника. Пока воин
успевает сократить дистанцию на 10 метров, лучник делает 2 попадания по воину.
Скорость атаки воина в 2 раза ниже, чем у лучника.

Написал такой вот код ( делал по одному образцу, но там задача была в разы проще) :

Код
--параметры испытаний
iterations = 1500000; -- итерации
timeout_limit = 1000; -- число попыток, если не убили за него, то ничья
distance=60; --расстояние между противниками

-- статы персонажей
char = {};
char [1] = {};
char [2] = {};

--лучник
char[1]["health"] = 600;
char[1]["damage"] = 10;
char[1]["chancetohit"] = 1;
char[1]["chancetocrit"] = 0.25;
char[1]["chancetosave"] = 0.40;
char[1]["attackspeed"] = 2;

char[2]["health"] = 800;
char[2]["damage"] = 25;
char[2]["chancetohit"] = 1;
char[2]["chancetoreduceto7"] = 0.50;
char[2]["attackspeed"] = 1;

-- обнуляем переменные
char_A_wins = 0;
char_B_wins = 0;
char_AB_wins = 0;
timeout_count = 0;

-- попал юнит или нет
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
maker-rusДата: Четверг, 15 Апреля 2021, 10:37 | Сообщение # 2
Гений
Сейчас нет на сайте
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
EvgenShetДата: Четверг, 29 Апреля 2021, 15:30 | Сообщение # 3
был не раз
Сейчас нет на сайте
Добавлено (29 Апреля 2021, 15:56)
---------------------------------------------
maker-rus, не помогло, выдает ошибку, решил избавится от функций archerAttack(), WarriorAttack() прописал их в основном цикле. Теперь считает, но по моему мнению не верно. если посчитать эту задачу руками, лучник выигрывает прям совсем на тоненького. Один лишний несейв лучником или сейв воином меняет ситуацию на противоположную, а моя прога выдает 99.9 случаев победы лучника, что-то я сделал не так


Сообщение отредактировал EvgenShet - Четверг, 29 Апреля 2021, 15:57
maker-rusДата: Пятница, 30 Апреля 2021, 20:33 | Сообщение # 4
Гений
Сейчас нет на сайте
Цитата EvgenShet ()
не помогло, выдает ошибку

Естественно, потому что есть еще одно такое присвоение и что важно - не одно, это касается и переменной char_A_health, я просто привел пример ошибки, а вы должны были проверить весь код на соответствие таким ошибкам по невнимательности, но вы решили пойти легким путем. Кроме этого, как я понимаю, вы не в курсе, чем отличается глобальная область видимости от локальной. Раз в цикле инициализируете переменную и потом ее пытаетесь использовать. Соответственно не слышали и про отступы (можно нажать кнопочку Tab или нажимать 4 раза пробел, это такая длинная кнопка внизу клавиатуры). Я попробовал реализовать ваш код, более - менее читаемо, вышло что-то в таком духе:
Код

--параметры испытаний
iterations          = 200000; -- итерации
limit_step_count    = 1000; -- число попыток, если не убили за него, то ничья
distance = 60; --расстояние между противниками

-- структура у всех объектов ОБЯЗАНА быть одинаковой
-- объекты персонажей

-- Лучник
local archer = {
    health            = 600,
    damage            = 10,
    chance_to_hit     = 0.35,
    chance_to_crit    = 0.25,
    chance_to_save    = 0.4,
    attack_speed      = 2,
    chance_to_reduce  = 0.5,
    win               = 0,
    lose              = 0,
    nobody            = 0
};

-- Воин
local warrior = {
    health            = 800,
    damage            = 25,
    chance_to_hit     = 0.1,
    chance_to_crit    = 0.25,
    chance_to_save    = 0.4,
    attack_speed      = 1,
    chance_to_reduce  = 0.5,
    win               = 0,
    lose              = 0,
    nobody            = 0
};

-- генератор случайных чисел
math.randomseed(os.time());

local function is_attack(chance_attack)
    local chance = math.random();
    return chance_attack > chance;
end

local function reset_player(archer, warrior)
    
    archer.health = 600;
    warrior.health = 800;
    
    return archer, warrior;
end

local function get_win(archer, warrior, count_step, limit_step)
    
    local win = {
        archer  = false,
        warrior = false,
        nobody  = false
    };
    
    -- победа воина
    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

print("Archer: \n");
local win_rate = " (" .. calc_win_rate(archer.win, archer.lose, archer.nobody) .. "%)";
print("\tCount win: " .. archer.win .. win_rate );
print("\tCount lose: " .. archer.lose);
print("\tCount nobody: " .. archer.nobody);

win_rate = " (" .. calc_win_rate(warrior.win, warrior.lose, warrior.nobody) .. "%)";
print("Warior: \n");
print("\tCount win: " .. warrior.win .. win_rate );
print("\tCount lose: " .. warrior.lose);
print("\tCount nobody: " .. warrior.nobody);



Все аккуратно и полностью работает.

Цитата EvgenShet ()
Теперь считает, но по моему мнению не верно. если посчитать эту задачу руками, лучник выигрывает прям совсем на тоненького

Если считать по тому принципу, что написан в коде, то там ни о каком "тоненьком" и "толстеньком" не идет речи. Там безоговорочная победа воина. Так как с шансом 1, который по факту равен 100%, то есть шанс атаки = 100%, выиграет однозначно воин.

Я немного поэкспериментировал и получил следующие результаты:
Код

Archer:

    Count win: 609 (47%)
    Count lose: 604
    Count nobody: 70
Warior:

    Count win: 604 (47%)
    Count lose: 609
    Count nobody: 70

lovegcup


Сообщение отредактировал maker-rus - Пятница, 30 Апреля 2021, 20:38
EvgenShetДата: Вторник, 04 Мая 2021, 13:21 | Сообщение # 5
был не раз
Сейчас нет на сайте
maker-rus, спасибо, конечно. но я вот читаю ваш код, и насколько я могу понять он вообще не соответствует условию задачи. почему-то когда бьет лучник, воин всегда снижает урон на 7, а не в 50% случаев. когда бьет воин лучник почему-то использует 50% процентный шанс воина на снижение урона, хотя он в 40% случаев полностью игнорирует урон. Еще я не совсем понял как у вас реализована двойная скорость атаки лучника. А еще вы не реализовали то, что лучник атакует дополнительное количество раз когда они сближаются ( но я тоже не придумал как это сделать, я совсем не программист, скорее начинающий гейм дизайнер) не удивительно что при таком раскладе у вас воин вышел победителем в большинстве случаев. у меня почему-то лучник почти всегда выигрывает, что тоже не совсем похоже на правду ( а я даже не учитывал доп атаки на сближении!!) На бумаге, при расчете этой задачи в средних значениях выигрывет лучник с разрывом в одну атаку буквально.
немного переделал ваш код ( не знаю как реализовать двойную скорость атаки лучника, потому написал блок с атакой лучника дважды :))

по результатам испытаний воин выигрывает в большем числе столкновений. это потому, что лучник каждый раз не делает дополнительные 12 (2*60/10) атак, моих знаний в этом языке недостаточно чтобы это реализовать, ХЕЛП


Сообщение отредактировал EvgenShet - Вторник, 04 Мая 2021, 13:42
maker-rusДата: Среда, 05 Мая 2021, 16:40 | Сообщение # 6
Гений
Сейчас нет на сайте
Цитата EvgenShet ()
спасибо, конечно. но я вот читаю ваш код, и насколько я могу понять он вообще не соответствует условию задачи.

Не за что, конечно. Он не должен соответствовать условиям задачи, он является примером, как следует оформить код и каким образом его вообще писать.
Цитата EvgenShet ()
почему-то когда бьет лучник, воин всегда снижает урон на 7

В моем решении нет зависимости от того, кто и когда бьет. В условии моего примера лучник выполняет свои действия отдельно, воин отдельно. Ничего подобного из того, что вы написали не выполняется. В условии для атаки воина, проверяется спас-бросок, если он выполняется - урон увеличивается, не выполняется - наносится обычный урон.
Цитата EvgenShet ()
а не в 50% случаев. когда бьет воин лучник почему-то использует 50% процентный шанс воина на снижение урона, хотя он в 40% случаев полностью игнорирует урон

Это реализуйте сами, хотите в 50% случаев, хотите в 30%, хотите в 63%, как вам будет удобно.

Цитата EvgenShet ()
Еще я не совсем понял как у вас реализована двойная скорость атаки лучника

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

Цитата EvgenShet ()
А еще вы не реализовали то, что лучник атакует дополнительное количество раз когда они сближаются ( но я тоже не придумал как это сделать, я совсем не программист, скорее начинающий гейм дизайнер) не удивительно что при таком раскладе у вас воин вышел победителем в большинстве случаев.

Я много чего не реализовал, потому что задачи такой перед собой не ставил, моя задача была не в том, что бы сделать все за вас, а предоставить базу, для улучшения и что бы другие это потом смогли прочитать, если потребуется еще помощь.
Читайте внимательно:
Цитата
Я попробовал реализовать ваш код, более - менее читаемо, вышло что-то в таком духе

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

Цитата EvgenShet ()
у меня почему-то лучник почти всегда выигрывает, что тоже не совсем похоже на правду ( а я даже не учитывал доп атаки на сближении!!)

Потому что вы используете другой код. Да, да, так бывает. Разный код, разные характеристики, разный результат.

Цитата EvgenShet ()
На бумаге, при расчете этой задачи в средних значениях выигрывет лучник с разрывом в одну атаку буквально.

Мне интересно, каким образом на бумаге вы рассчитываете псевдослучайные числа? Есть большие сомнения в правильности ваших вычислений. Либо вы, одновременно, кроме того, что дизайнер, еще и Нострадамус.

Цитата EvgenShet ()
немного переделал ваш код ( не знаю как реализовать двойную скорость атаки лучника, потому написал блок с атакой лучника дважды :))

И снова - здарова. Я правильно понимаю, что вы ничему не учитесь? Посмотрите на мой код, а потом на свой. Чем они отличаются?

Цитата EvgenShet ()
по результатам испытаний воин выигрывает в большем числе столкновений. это потому, что лучник каждый раз не делает дополнительные 12 (2*60/10) атак, моих знаний в этом языке недостаточно чтобы это реализовать, ХЕЛП

Ваших знаний не только в скриптовом языке маловато, к сожалению. Распишите корректно, что и как должно у вас выполняться. Потому что на данный момент я вижу следующее в ваших словах: "мгм... лучник живет на дереве и он должен ускоряться на 50% процентов, а воин не должен ускоряться, он должен махать топором, поэтому когда он вращается - лучник танцует, а это значит, что дерево должно гнуться, из-за этого Король Империи Гномов объявил войну великанам."

^_^
EvgenShetДата: Четверг, 06 Мая 2021, 17:18 | Сообщение # 7
был не раз
Сейчас нет на сайте
maker-rus, А вот оно что, это пример отличный от моего, окей. Что я не могу сейчас понять: По моим условиям до реализации цикла ( два удара лучника, удар воина, повторить до тех пор пока кто-то не помрет) должны быть несколько атак лучника. Как мне записать эти атаки чтобы они выполнялись в начале схватки каждый из n количества боев, но при этом не повторялись каждый шаг боя.
maker-rusДата: Пятница, 07 Мая 2021, 19:09 | Сообщение # 8
Гений
Сейчас нет на сайте
Цитата EvgenShet ()
Как мне записать эти атаки чтобы они выполнялись в начале схватки каждый из n количества боев, но при этом не повторялись каждый шаг боя.

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

lovegcup
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг