Подтвердить что ты не робот

Как округлить до определенных значений в Python

Я работаю над алгоритмом автоматического создания персональных листов для ролевой игры. В игре у вас есть атрибуты, на которые вы добавляете очки, чтобы увеличить их. Однако при определенном значении требуется 2 балла, чтобы увеличить значение фактического атрибута на 1. Вы начинаете с определенного количества точек, и каждый атрибут имеет значение по умолчанию

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

Например, если я наложу 3 очка в "силе", это нормально, я получаю значение "сила" 3 (включая базу 1). Однако, если я ставлю 4 очка, я все равно должен иметь значение 4. Для получения значения 5. он должен взять 5 очков (плюс основание 1). Затем он получает еще 2 балла, чтобы получить значение 6, 3 балла, чтобы получить значение 7 и 3 точки, чтобы получить значение 8.

Код, который я использую для назначения attitutes, выглядит следующим образом:

attributes = {}
row1 = ['strength', 'intelligence', 'charisma']
row2 = ['stamina', 'willpower']
row3 = ['dexterity', 'wits', 'luck']

def assignRow(row, p): # p is the number of points you have to assign to each row
    rowValues = {}
    for i in range(0, len(row)-1):
        val = randint(0, p)
        rowValues[row[i]] = val + 1
        p -= val
    rowValues[row[-1]] = p + 1
    return attributes.update(rowValues)

assignRow(row1, 7)
assignRow(row2, 5)
assignRow(row3, 3)

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

то есть. "strength": 4 остается как "strength": 4, но "wits": 6" переходит на "wits": 5", а "intelligence: 9 переходит на "intelligence: 7".

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

def convert(list):
    for i in range(len(list)):
        if list[i] <= 4:
            list[i] = list[i]
        if list[i] in (5, 6):
            list[i] -= 1
        if list[i] in (7, 8):
            list[i] -= 2
        if list[i] in (9, 10):
            list[i] = 6
        if list[i] in (11, 12, 13):
            list[i] = 7
        else:
            list[i] = 8

Неэффективен или симпатичен, но все еще является решением. Однако вы не можете просто перебирать индексы в словаре, поэтому я не совсем уверен, как это сделать.

Было бы оценено общее объяснение или функция.

4b9b3361

Ответ 1

Кажется, что bisection algo подходит для ваших нужд довольно хорошо - точки для "инвестирования" всегда сортируются и определяются. Создайте массив с референтными точками, и вам будет удобно без связки if s:

>>> from bisect import bisect
>>> points_to_invest = [1, 2, 3, 4, 6, 8, 10, 13]
>>> bisect(points_to_invest, 1)
1
>>> bisect(points_to_invest, 4)
4
>>> bisect(points_to_invest, 5)
4
>>> bisect(points_to_invest, 6)
5

Этот подход облегчит вам поддержку в будущем

Ответ 2

Вы можете перебирать элементы с помощью dictionary.items() Затем вы можете изменить свою функцию преобразования:

def convert(attributes):
    for key, value in attributes.items():
        # do your conversion on value here
        if value <= 4:
            continue # do nothing for this element
        elif value in (5, 6):
            value -= 1
        elif value in (7, 8):
            value -= 2
        elif value in (9, 10):
            value = 6
        elif value in (11, 12, 13):
            value = 7
        else:
            value = 8

        # to replace the value in the dictionary you can use
        attributes[key] = new_value

Ответ 3

Немного меньше места, чем ваша функция "convert", хотя все же ручной труд:

p_to_v = {1:1, 2:2, 3:3, 4:4, 5:4, 6:5, 7:5, 8:6} # 'translator' dict, fill up further
input = {'strength':6, 'wits':8} # dict with stats and their points
output = dict((stat, p_to_v[point]) for stat, point in input.items()) # {'strength':5, 'wits':6}

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

Ответ 4

После многих проб и ошибок здесь используется однострочная функция:

def convert(x):
    return x - (x > 4) - (x > 6) - (x > 8) * (x - 8) + (x > 10) + (x > 13)

Здесь тест:

print([(points, convert(points)) for points in range(20)])
# [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 4), (6, 5), (7, 5), (8, 6), (9, 6), (10, 6), (11, 7), (12, 7), (13, 7), (14, 8), (15, 8), (16, 8), (17, 8), (18, 8), (19, 8)]

if и elif могут быть более четкими.

Эта функция просто преобразует количество входных точек в значение. Вы можете применить функцию convert к каждому элементу списка.