Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-
This commit is contained in:
spinerak
2024-07-06 21:18:59 +02:00
parent d12218166b
commit 577fb744f6
3 changed files with 24 additions and 4601 deletions

View File

@@ -16,43 +16,6 @@ from .YachtWeights import yacht_weights
# We then pick a correct percentile to reflect the correct score that should be in logic.
# The score is logic is *much* lower than the actual maximum reachable score.
# List of categories, and the name of the logic class associated with it
category_mappings = {
"Category Ones": "Ones",
"Category Twos": "Twos",
"Category Threes": "Threes",
"Category Fours": "Fours",
"Category Fives": "Fives",
"Category Sixes": "Sixes",
"Category Choice": "Choice",
"Category Inverse Choice": "Choice",
"Category Pair": "Pair",
"Category Three of a Kind": "ThreeOfAKind",
"Category Four of a Kind": "FourOfAKind",
"Category Tiny Straight": "TinyStraight",
"Category Small Straight": "SmallStraight",
"Category Large Straight": "LargeStraight",
"Category Full House": "FullHouse",
"Category Yacht": "Yacht",
"Category Distincts": "Distincts",
"Category Two times Ones": "Twos", # same weights as twos category
"Category Half of Sixes": "Threes", # same weights as threes category
"Category Twos and Threes": "TwosAndThrees",
"Category Sum of Odds": "SumOfOdds",
"Category Sum of Evens": "SumOfEvens",
"Category Double Threes and Fours": "DoubleThreesAndFours",
"Category Quadruple Ones and Twos": "QuadrupleOnesAndTwos",
"Category Micro Straight": "MicroStraight",
"Category Three Odds": "ThreeOdds",
"Category 1-2-1 Consecutive": "OneTwoOneConsecutive",
"Category Three Distinct Dice": "ThreeDistinctDice",
"Category Two Pair": "TwoPair",
"Category 2-1-2 Consecutive": "TwoOneTwoConsecutive",
"Category Five Distinct Dice": "FiveDistinctDice",
"Category 4&5 Full House": "FourAndFiveFullHouse",
}
class Category:
def __init__(self, name, quantity=1):
self.name = name
@@ -60,7 +23,7 @@ class Category:
# return mean score of a category
def mean_score(self, num_dice, num_rolls):
if num_dice == 0 or num_rolls == 0:
if num_dice <= 0 or num_rolls <= 0:
return 0
mean_score = 0
for key, value in yacht_weights[self.name, min(8, num_dice), min(8, num_rolls)].items():
@@ -77,7 +40,7 @@ class ListState:
return self.item_counts[item]
def extract_progression(state, player, frags_per_dice, frags_per_roll):
def extract_progression(state, player, frags_per_dice, frags_per_roll, allowed_categories):
"""
method to obtain a list of what items the player has.
this includes categories, dice, rolls and score multiplier etc.
@@ -92,8 +55,8 @@ def extract_progression(state, player, frags_per_dice, frags_per_roll):
number_of_step_mults = state.count("Step Score Multiplier", player)
categories = [
Category(category_value, state.count(category_name, player))
for category_name, category_value in category_mappings.items()
Category(category_name, state.count(category_name, player))
for category_name in allowed_categories
if state.count(category_name, player) # want all categories that have count >= 1
]
@@ -133,10 +96,7 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
if player not in yachtdice_cache:
yachtdice_cache[player] = {}
# if already computed, return the result
if tup in yachtdice_cache[player]:
# index = list(yachtdice_cache[player].keys()).index(tup) # Get the index of tup in the keys list
# print(f"Using cache {player} {index} / {len(yachtdice_cache[player])}")
return yachtdice_cache[player][tup]
# sort categories because for the step multiplier, you will want low-scoring categories first
@@ -193,7 +153,7 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
# calculate total distribution
total_dist = {0: 1}
for j, category in enumerate(categories):
if num_dice == 0 or num_rolls == 0:
if num_dice <= 0 or num_rolls <= 0:
dist = {0: 100000}
else:
dist = yacht_weights[category.name, min(8, num_dice), min(8, num_rolls)].copy()
@@ -224,20 +184,20 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
return yachtdice_cache[player][tup]
def dice_simulation_fill_pool(state, frags_per_dice, frags_per_roll, difficulty, player):
def dice_simulation_fill_pool(state, frags_per_dice, frags_per_roll, allowed_categories, difficulty, player):
"""
Returns the feasible score that one can reach with the current state, options and difficulty.
This function is called with state being a list, during filling of item pool.
"""
categories, num_dice, num_rolls, fixed_mult, step_mult, expoints = extract_progression(
state, "state_is_a_list", frags_per_dice, frags_per_roll
state, "state_is_a_list", frags_per_dice, frags_per_roll, allowed_categories
)
return (
dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mult, difficulty, player) + expoints
)
def dice_simulation_state_change(state, player, frags_per_dice, frags_per_roll, difficulty):
def dice_simulation_state_change(state, player, frags_per_dice, frags_per_roll, allowed_categories, difficulty):
"""
Returns the feasible score that one can reach with the current state, options and difficulty.
This function is called with state being a AP state object, while doing access rules.
@@ -246,7 +206,7 @@ def dice_simulation_state_change(state, player, frags_per_dice, frags_per_roll,
if state.prog_items[player]["state_is_fresh"] == 0:
state.prog_items[player]["state_is_fresh"] = 1
categories, num_dice, num_rolls, fixed_mult, step_mult, expoints = extract_progression(
state, player, frags_per_dice, frags_per_roll
state, player, frags_per_dice, frags_per_roll, allowed_categories
)
state.prog_items[player]["maximum_achievable_score"] = (
dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mult, difficulty, player)
@@ -256,16 +216,16 @@ def dice_simulation_state_change(state, player, frags_per_dice, frags_per_roll,
return state.prog_items[player]["maximum_achievable_score"]
def set_yacht_rules(world: MultiWorld, player: int, frags_per_dice, frags_per_roll, difficulty):
def set_yacht_rules(world: MultiWorld, player: int, frags_per_dice, frags_per_roll, allowed_categories, difficulty):
"""
Sets rules on entrances and advancements that are always applied
Sets rules on reaching scores
"""
for location in world.get_locations(player):
set_rule(
location,
lambda state, curscore=location.yacht_dice_score, player=player: dice_simulation_state_change(
state, player, frags_per_dice, frags_per_roll, difficulty
state, player, frags_per_dice, frags_per_roll, allowed_categories, difficulty
)
>= curscore,
)

File diff suppressed because one or more lines are too long

View File

@@ -56,7 +56,7 @@ class YachtDiceWorld(World):
item_name_groups = item_groups
ap_world_version = "2.0.6"
ap_world_version = "2.1.0"
def _get_yachtdice_data(self):
return {
@@ -142,10 +142,10 @@ class YachtDiceWorld(World):
]
# categories used in this game.
possible_categories = []
self.possible_categories = []
for index, cats in enumerate(all_categories):
possible_categories.append(cats[categorylist[index]])
self.possible_categories.append(cats[categorylist[index]])
# Add Choice and Inverse choice (or their alts) to the precollected list.
if index == 0 or index == 1:
@@ -264,7 +264,7 @@ class YachtDiceWorld(World):
# which often don't give any points, until you get overpowered, and then they give all points.
cat_weights = [2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
weights["Double category"] /= 1.1
return self.random.choices(possible_categories, weights=cat_weights)[0]
return self.random.choices(self.possible_categories, weights=cat_weights)[0]
elif which_item_to_add == "Points":
score_dist = self.options.points_size
probs = {"1 Point": 1, "10 Points": 0, "100 Points": 0}
@@ -301,7 +301,7 @@ class YachtDiceWorld(World):
self.itempool.append(get_item_to_add(weights, extra_points_added, multipliers_added, items_added))
score_in_logic = dice_simulation_fill_pool(
self.itempool + self.precollected, self.frags_per_dice, self.frags_per_roll, self.difficulty, self.player
self.itempool + self.precollected, self.frags_per_dice, self.frags_per_roll, self.possible_categories, self.difficulty, self.player
)
# if we overshoot, remove items until you get below 1000, then return the last removed item
@@ -313,6 +313,7 @@ class YachtDiceWorld(World):
self.itempool + self.precollected,
self.frags_per_dice,
self.frags_per_roll,
self.possible_categories,
self.difficulty,
self.player,
)
@@ -333,6 +334,7 @@ class YachtDiceWorld(World):
self.itempool + self.precollected,
self.frags_per_dice,
self.frags_per_roll,
self.possible_categories,
self.difficulty,
self.player,
)
@@ -443,7 +445,7 @@ class YachtDiceWorld(World):
"""
set rules per location, and add the rule for beating the game
"""
set_yacht_rules(self.multiworld, self.player, self.frags_per_dice, self.frags_per_roll, self.difficulty)
set_yacht_rules(self.multiworld, self.player, self.frags_per_dice, self.frags_per_roll, self.possible_categories, self.difficulty)
set_yacht_completion_rules(self.multiworld, self.player)
def fill_slot_data(self):
@@ -463,6 +465,7 @@ class YachtDiceWorld(World):
slot_data = {**yacht_dice_data, **yacht_dice_options} # combine the two
slot_data["goal_score"] = self.goal_score
slot_data["last_check_score"] = self.max_score
slot_data["allowed_categories"] = self.possible_categories
slot_data["ap_world_version"] = self.ap_world_version
return slot_data