Comment arrondir à des valeurs spécifiques en Python

je travaille sur un algorithme pour créer automatiquement des feuilles de caractères pour un jeu de rôle. Dans le jeu, vous avez des attributs dans lesquels vous mettez des points pour les augmenter. Cependant, à une certaine valeur, il faut 2 points pour augmenter la valeur de l'attribut par 1. Vous commencez avec un certain nombre de points, et chaque attribut a une valeur de 1 par défaut

j'ai un programme qui assigne au hasard les points, cependant je suis coincé quant à la façon dont je change alors ces valeurs (qui sont dans un dictionnaire) pour arrondir vers le bas si nécessaire.

par exemple, si je mets 3 points dans "strength", thats fine, j'obtiens une valeur de" strength " de 3 (incluant la base 1). Cependant, si je mets 4 points, Je ne devrais encore avoir qu'une valeur de 4. Il devrait prendre 5 points (plus la base 1) afin d'obtenir une valeur de 5. Il faut ensuite 2 autres points pour obtenir une valeur de 6, 3 points pour obtenir une valeur de 7 et 3 points pour obtenir une valeur de 8.

Le code que j'utilise actuellement pour attribuer l'attribue ressemble à ceci:

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)

ce que je veux est juste une fonction simple qui prend le dictionnaire "attributs" comme paramètre, et convertit le nombre de points que chaque attribut A à la valeur appropriée qu'il devrait être.

i.e. "strength": 4 reste descend "wits": 5" et "intelligence: 9 descend "intelligence: 7".

je suis un peu nouveau à l'utilisation des dictionnaires et donc les façons dont je m'approcherais normalement ceci:

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

pas efficace ou jolie mais tout de même une solution. Cependant, vous ne pouvez pas simplement boucler les index dans un dictionnaire donc je ne suis pas entièrement sûr de savoir comment faire quelque chose comme ça.

une explication ou une fonction générale serait appréciée.

10
demandé sur Freddie R 2017-07-26 18:34:39

4 réponses

Semble que bissection algo répond à vos besoins assez bien - les points à "investir" sont toujours triés et définis. Créer tableau avec des points de référence et vous êtes bon à Sans tas de 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

cette approche vous facilitera la maintenabilité pour l'avenir

7
répondu Slam 2017-07-26 16:10:36

vous pouvez boucler les éléments en utilisant dictionary.items() Vous pouvez alors modifier votre fonction convert:

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
2
répondu BlaXXuN 2017-07-26 15:59:57

un peu moins d'espace que votre fonction "convert", bien qu'encore manuelle:

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}

si vous voulez que votre "traducteur" prenne moins de travail manuel et une meilleure échelle, alors vous pouvez le pré-générer via un certain code, en fonction de votre logique de points vers des valeurs.

1
répondu Dmitry Sutyagin 2017-07-26 16:09:32

après de nombreux essais et erreurs, voici une fonction à une seule doublure:

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

Voici un test:

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 et elif les déclarations pourraient être plus claires, cependant.

cette fonction convertit simplement une quantité de points d'entrée en valeur. Vous pouvez appliquer convert fonction à chaque élément d'une liste.

0
répondu Eric Duminil 2017-07-26 16:04:00