Подсчитать прогресс активности

есть прогресс бар который заполняется на 100% когда пользователь потратит определенное кол-во денег, например 100т

до 80% нужно что бы 100р было равно 1%

после 80% и до 90% 1000р=1%

после 90% и до 100% 10000р=1%

есть функция, в которой проблема

function getActivityLevelPercent($money, $level){
    $activity_level = $level;
    $d = 100;

    if($activity_level >= 80)$d = 1000;
    if($activity_level >= 90)$d = 10000;
    $add_percent = $money/$d;
    return round($add_percent, 2);
}

если например имея прогресс от 0-80, то потраченные 10000р поднимут прогресс до 100%

подскажите как пропорционально и правильно увеличивать прогресс


Ответы (2 шт):

Автор решения: pgood

Необходимо контролировать количество добавляемых процентов в зависимости от количества уже имеющихся. Вычисляем лимит (количество процентов, которое мы можем добавить до ближайшего барьера 80/90/100) и переводим в проценты столько денег, сколько в него влазит, далее запускаем рекурсию для оставшихся денег. Код сильно не отлаживал, возможны ошибки, но основную идею он передает:

function getActivityLevelPercent($money, $level){
    if($level < 80){
        $d = 100;
        $max_percent = 80 - $level;
    }elseif($level < 90){
        $d = 1000;
        $max_percent = 90 - $level;
    }elseif($level < 100){
        $d = 10000;
        $max_percent = 100 - $level;
    }else{
        return 0;
    }
    $max_money = $max_percent * $d;
    if($money > $max_money){
        return $max_percent + getActivityLevelPercent(
                $money - $max_money,
                $level + $max_percent
            );
    }
    return $money / $d;
}

Можно сделать универсальнее и переписать так:

function getActivityLevelPercent($money, $level){
    $ranges = [
        80 => 100,
        90 => 1000,
        100 => 10000,
    ];
    foreach($ranges as $level_border => $percent_cost){
        if($level < $level_border){
            $max_percent = $level_border - $level;
            $max_money = $max_percent * $percent_cost;
            if($money > $max_money){
                return $max_percent + getActivityLevelPercent(
                        $money - $max_money,
                        $level + $max_percent
                    );
            }
            return $money / $percent_cost;
        }
    }
    return 0;
}
→ Ссылка
Автор решения: Егор Банин

Как я понимаю, вы хотите создать прогресс-бар, который быстро заполняется в начале и всё медленнее в конце. Если так, то требования, которые вы сформулировали в задаче, неверные (0.1 * 0.8 + 1 * 0.1 + 10 * 0.1 = 1,18 -- 118%). Можно поправить коэффициенты. Надо разделить 100 процентов денег на три части, например: 20, 30, 50, при этом 20 процентов денег заполнят 80 процентов прогресс-бара, следующие 30 -- 10 процентов прогресс-бара и остальные 50 -- оставшиеся 10 процентов прогресс-бара. Мы будто растягиваем и сжимаем прогресс-бар на разных участках. Можно написать функцию, которая считает эти искажения:

<?php

function transformProgress(float $ratio): float {
    $progress = min($ratio, 0.2) * (0.8 / 0.2); // первые 20% должны распределиться на участке до 80% прогресс-бара

    if ($ratio > 0.2) {
        $progress += min($ratio - 0.2, 0.3) * (0.1 / 0.3); // следуюющие 30% -- на 10% прогресс-бара 
    }

    if ($ratio > 0.5) {
        $progress += ($ratio - 0.5) * (0.1 / 0.5); // последние 50% -- на 10% прогресс-бара
    }

    return $progress;
}

var_dump(transformProgress(0.01)); // потрачено 1% денег -- 4% на прогресс-баре
var_dump(transformProgress(0.2)); // потрачено 20% денег -- 80% на прогресс-баре
var_dump(transformProgress(0.21)); // потрачено 21% денег -- 80,3% на прогресс-баре
var_dump(transformProgress(0.5)); // потрачено 50% денег -- 90% на прогресс-баре
var_dump(transformProgress(0.51)); // потрачено 51% денег -- 90.2% на прогресс-баре
var_dump(transformProgress(1.0)); // потрачено 100% денег -- 100% на прогресс-баре
var_dump(transformProgress(0.0)); // потрачено 0% денег -- 0% на прогресс-баре

Как видно, функция никак не зависит от количества денег и управляется просто набором констант -- получает y из x. Из школьного курса математики можно вспомнить множество таких функций, некоторые ведут себя похожим образом. Например функция y = √x.

<?php

function transformProgress(float $ratio): float {
    return $ratio ** (1 / 5);
}

Обратите внимание, что в этом случае гораздо удобнее представлять проценты как часть целого, то есть число от 0 до 1.

→ Ссылка