diff --git a/roller.py b/roller.py new file mode 100644 index 0000000..6566f31 --- /dev/null +++ b/roller.py @@ -0,0 +1,192 @@ +import random +import time + + +def new_character_roller(primary_stat, secondary_stat, min_pstat, min_stat, max_stat, max_stats_allowed, + max_stat_expected, odd_allowed, counter): + result = [8, 8, 8, 8, 8, 8] + ps = stat_translator(primary_stat) + ss = stat_translator(secondary_stat) + + if ps is None or ss is None: + return None + + # Reroll whole set if any of these things are true: Primary Stat too low, Secondary Stat too low, Some Stat too low + # rolls have too many good numbers or not enough good numbers, too many odd numbers + while result[ps] < min_pstat or result[ss] < (min_pstat - 2) or lowest_roll(result) < min_stat or result[2] < 10 \ + or not is_buff(result, max_stat, max_stats_allowed, max_stat_expected) or odds_allowed(result, odd_allowed): + for i in range(len(result)): + result[i] = roll_4d6d11(counter) + counter[1] += 1 + return result + + +def roll_4d6d11(counter): + low = 7 + sum_hold = 0 + for x in range(4): + roll = random.randint(1, 6) + sum_hold += roll + + if roll < low: + low = roll + counter[0] += 1 + return sum_hold - low + + +def stat_translator(stat_name): + if stat_name == 'Str': + return 0 + elif stat_name == 'Dex': + return 1 + elif stat_name == 'Con': + return 2 + elif stat_name == 'Int': + return 3 + elif stat_name == 'Wis': + return 4 + elif stat_name == 'Cha': + return 5 + else: + print("Unmatched Primary Stat") + return None + + +def lowest_roll(rolls): + low = 20 + for roll in rolls: + if roll < low: + low = roll + return low + + +def odds_allowed(rolls, odd_tolerance): + count = 0 + for roll in rolls: + if roll % 2 == 1: + count += 1 + # if odd_tolerance >= count: + # print("Character Odd Stat test failed.") + return odd_tolerance < count + + +def is_buff(rolls, max_tolerance, max_allowed, max_expected): + count = 0 + for roll in rolls: + if roll >= max_tolerance: + count += 1 + # if max_expected > count or count > max_allowed: + # print("Character Buff test failed.") + return max_expected <= count <= max_allowed + + +def party_roller(separation, sum_min, sum_max, stat_priority, a, b, c, d, e, f, counter): + stat_group = [] + i = 0 + + while len(stat_group) < len(stat_priority): + roll_set = new_character_roller(stat_priority[i][0], stat_priority[i][1], a, b, c, d, e, f, counter) + if roll_set is None: + print("New Character Roller returned None, address this error and try again.") + stat_group.append(roll_set) + i += 1 + + if len(stat_group) == len(stat_priority) and (\ + not group_within_separation(stat_group, separation) or + not group_set_range(stat_group, sum_max, sum_min) or + not snowflakes(stat_group, stat_priority)): + # print("Party Requirements Failed.") + stat_group = [] + i = 0 + counter[2] += 1 + if counter[2] % 10000 == 0: + print("Still working.") + return stat_group + + +def group_set_range(stat_set, max_sum, min_sum): + result = True + for ss in stat_set: + sum_hold = 0 + for s in ss: + sum_hold += s + result &= min_sum <= sum_hold <= max_sum + # if not result: + # print("Group Range test failed.") + return result + + +def group_within_separation(stat_set, separation): + lowest = 1000 + biggest = 0 + + for ss in stat_set: + sum_hold = 0 + for s in ss: + sum_hold += s + if sum_hold < lowest: + lowest = sum_hold + if sum_hold > biggest: + biggest = sum_hold + + # if biggest-lowest > separation: + # print("Group Separation test failed.") + return biggest-lowest <= separation + + +def snowflakes(stat_set, snowflake_set): + result = True + + for ss in stat_set: + ss_index = stat_set.index(ss) + ss_ps = stat_translator(snowflake_set[ss_index][0]) + + for s in stat_set: + s_index = stat_set.index(s) + s_ps = stat_translator(snowflake_set[s_index][0]) + if s != ss and ss_ps != s_ps: + result &= s[ss_ps] < ss[ss_ps] + # if not result: + # print("Snowflake test failed.") + return result + + +def taber(stat_set, index): + longest_string = 0 + result = "\t" + + for ss in stat_set: + if len(str(ss)) > longest_string: + longest_string = len(str(ss)) + + difference = longest_string - len(str(stat_set[index])) + extra_tabs = int(difference/4) + + for i in range(extra_tabs): + result += "\t" + if difference % 4 > 0: + result += "\t" + return result + + +c = [0, 0, 1] +stat_time = time.time() +# 1) Primary Stat +# 2) Secondary Stat +# 3) Primary Stat Low Value (exclusive) +# 4) Global Low Value (exclusive) +# 5) Global High Value (inclusive) +# 6) Upper Limit (inclusive) of rolls as large or greater than Global High Value +# 7) Lower Limit (inclusive) of rolls at least as large as Global High Value +# 8) Number of odd roles allowed (inclusive) +# 9) How distant sum of each character's stats can be - player balance +# 10) Upper bound for each player stat sum (inclusive bound) - standard fantasy is 15 point buy on top of 10's, so 75 +# 11) Lower bound for each player stat sum (inclusive bound) +# See key above 9 10 11 1 2 1 2 1 2 1 2 3 4 5 6 7 8 +stats = party_roller(0, 74, 76, [["Wis", "Str"], ["Cha", "Wis"], ["Int", "Cha"], ["Cha", "Dex"]], 14, 7, 16, 2, 1, 3, c) +print("Inquisitor roll is\t" + str(stats[0]) + taber(stats, 0) + "sum: " + str(sum(s for s in stats[0]))) +print("Sorcerer roll is\t" + str(stats[1]) + taber(stats, 1) + "sum: " + str(sum(s for s in stats[1]))) +print("Psychic roll is\t\t" + str(stats[2]) + taber(stats, 2) + "sum: " + str(sum(s for s in stats[2]))) +print("Rouge roll is\t\t" + str(stats[3]) + taber(stats, 3) + "sum: " + str(sum(s for s in stats[3]))) +print("Finding the Magic Rolls took " + str(round((time.time() - stat_time)/60, 3)) + " minutes.") +print(str(c[0]) + " rolls were made for " + str(c[1]) + " characters in " + str(c[2]) + " parties.")