Reputation: 387
I am working on an algorithm to automatically create character sheets for a roleplaying game. In the game, you have attributes which you put points into to increase them. However, at a certain value it takes 2 points to increase the value of the actual attribute by 1. You start of with a certain number of points, and each attribute has a value of 1 by default
I have a program that randomly assigns the points, however I am stuck as to how I then change these values (that are in a dictionary) to round down when necessary.
For example, if I put 3 points in "strength", thats fine, I get a "strength" value of 3 (including tha base 1). However, if I put 4 points in, I still should only have a value of 4. It should take 5 points (plus the base 1) in order to get a value of 5. It then takes another 2 points to get a value of 6, 3 points to get a value of 7 and 3 points to get a value of 8.
The code I am currently using to assign the attibutes looks like this:
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)
What I want is just a simple function that takes the dictionary "attributes" as a parameter, and converts the number of points each attribute has to the proper value it should be.
i.e. "strength": 4
stays as "strength": 4
, but "wits": 6"
goes down to "wits": 5"
, and "intelligence: 9
goes down to "intelligence: 7"
.
I'm somewhat new to using dictionaries and so the ways I would normally approach this:
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
Not efficient or pretty but still a solutuion. However, you can't just loop over indexes in a dictionary so I am not entirely sure how to go about something like this.
General explanation or function would be appreciated.
Upvotes: 10
Views: 2014
Reputation: 8572
Seems that bisection algo suits your needs pretty well - points to "invest" is always sorted and defined. Create array with reference points and you're good to without bunch of 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
This approach will give you way easier maintainability for future
Upvotes: 6
Reputation: 571
A bit less space then your "convert" function, though still manual labor:
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}
If you want your 'translator' to take less manual work and scale better then you can pre-generate it via some code, depending on your logic of points to values.
Upvotes: 1
Reputation: 54223
After many trial and error, here's a one-liner function:
def convert(x):
return x - (x > 4) - (x > 6) - (x > 8) * (x - 8) + (x > 10) + (x > 13)
Here's a 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
and elif
statements might be clearer, though.
This function simply converts an amount of input points to a value. You can apply the convert
function to each element of a list.
Upvotes: 0
Reputation: 121
You can loop over the elements by using dictionary.items()
You can then modify your convert function:
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
Upvotes: 2