Comments and editing

This commit is contained in:
spinerak
2024-06-06 22:54:40 +02:00
parent be65762532
commit 1e935fb9e8
4 changed files with 44 additions and 54 deletions

View File

@@ -11,6 +11,7 @@ class YachtDiceItem(Item):
#the starting index is chosen semi-randomly to be 16871244000
item_table = {
#victory item, always placed manually at goal location
"Victory": ItemData(16871244000-1, ItemClassification.progression),
"Dice": ItemData(16871244000, ItemClassification.progression),
@@ -18,7 +19,7 @@ item_table = {
"Roll": ItemData(16871244002, ItemClassification.progression),
"Roll Fragment": ItemData(16871244003, ItemClassification.progression),
"Score Multiplier": ItemData(16871244004, ItemClassification.progression),
#"Score Multiplier": ItemData(16871244004, ItemClassification.progression), #not used anymore
"Fixed Score Multiplier": ItemData(16871244005, ItemClassification.progression),
"Step Score Multiplier": ItemData(16871244006, ItemClassification.progression),
@@ -28,10 +29,8 @@ item_table = {
"Category Fours": ItemData(16871244106, ItemClassification.progression),
"Category Fives": ItemData(16871244107, ItemClassification.progression),
"Category Sixes": ItemData(16871244108, ItemClassification.progression),
"Category Choice": ItemData(16871244109, ItemClassification.progression),
"Category Inverse Choice": ItemData(16871244110, ItemClassification.progression),
"Category Pair": ItemData(16871244111, ItemClassification.progression),
"Category Three of a Kind": ItemData(16871244112, ItemClassification.progression),
"Category Four of a Kind": ItemData(16871244113, ItemClassification.progression),
@@ -47,10 +46,8 @@ item_table = {
"Category Twos and Threes": ItemData(16871244126, ItemClassification.progression),
"Category Sum of Odds": ItemData(16871244127, ItemClassification.progression),
"Category Sum of Evens": ItemData(16871244128, ItemClassification.progression),
"Category Double Threes and Fours": ItemData(16871244129, ItemClassification.progression),
"Category Quadruple Ones and Twos": ItemData(16871244130, ItemClassification.progression),
"Category Micro Straight": ItemData(16871244131, ItemClassification.progression),
"Category Three Odds": ItemData(16871244132, ItemClassification.progression),
"Category 1-2-1 Consecutive": ItemData(16871244133, ItemClassification.progression),
@@ -60,7 +57,7 @@ item_table = {
"Category Five Distinct Dice": ItemData(16871244137, ItemClassification.progression),
"Category 4&5 Full House": ItemData(16871244138, ItemClassification.progression),
#filler items
"Encouragement": ItemData(16871244200, ItemClassification.filler),
"Fun Fact": ItemData(16871244201, ItemClassification.filler),
"Story Chapter": ItemData(16871244202, ItemClassification.filler),
@@ -68,14 +65,15 @@ item_table = {
"Bad RNG": ItemData(16871244204, ItemClassification.trap),
"Bonus Point": ItemData(16871244205, ItemClassification.useful), #not included in logic
#These points are included in the logic and might be necessary to progress.
"1 Point": ItemData(16871244301, ItemClassification.progression_skip_balancing),
"10 Points": ItemData(16871244302, ItemClassification.progression),
"100 Points": ItemData(16871244303, ItemClassification.progression)
}
#item groups for better hinting
item_groups = {
"Score Multiplier": {
"Score Multiplier",
"Step Score Multiplier",
"Fixed Score Multiplier"
},
@@ -86,10 +84,8 @@ item_groups = {
"Category Fours",
"Category Fives",
"Category Sixes",
"Category Choice",
"Category Inverse Choice",
"Category Pair",
"Category Three of a Kind",
"Category Four of a Kind",
@@ -98,17 +94,14 @@ item_groups = {
"Category Large Straight",
"Category Full House",
"Category Yacht",
"Category Distincts",
"Category Two times Ones",
"Category Half of Sixes",
"Category Twos and Threes",
"Category Sum of Odds",
"Category Sum of Evens",
"Category Double Threes and Fours",
"Category Quadruple Ones and Twos",
"Category Micro Straight",
"Category Three Odds",
"Category 1-2-1 Consecutive",

View File

@@ -32,7 +32,7 @@ def ini_locations(goal_score, max_score, num_locs, dif):
if dif == 1:
scaling = 3
elif dif == 2:
scaling = 2.2
scaling = 2.3
scores = []
#the scores follow the function int( 1 + (perc ** scaling) * (max_score-1) )
@@ -64,5 +64,4 @@ def ini_locations(goal_score, max_score, num_locs, dif):
lookup_id_to_name: typing.Dict[int, str] = {data.id: item_name for item_name, data in all_locations.items() if data.id}
# we need to run this function to initialize all scores from 1 to 1000, even though not all are used
# this in order to make sure no other worlds use any ids that are similar to Yacht Dice
all_locations = all_locations_fun(1000)

View File

@@ -4,6 +4,7 @@ from .YachtWeights import yacht_weights
import math
from collections import defaultdict
#List of categories, and the name of the logic class associated with it
category_mappings = {
"Category Ones": "Ones",
"Category Twos": "Twos",
@@ -49,7 +50,6 @@ category_mappings = {
#The score is logic is *much* lower than the actual maximum reachable score.
class Category:
def __init__(self, name, quantity = 1):
self.name = name
@@ -65,12 +65,11 @@ class Category:
return mean_score * self.quantity
def extract_progression(state, player, options):
#method to obtain a list of what items the player has.
#this includes categories, dice, rolls and score multiplier.
#this includes categories, dice, rolls and score multiplier etc.
if player == "state_is_a_list":
if player == "state_is_a_list": #the state variable is just a list with the names of the items
number_of_dice = (
state.count("Dice")
+ state.count("Dice Fragment") // options.number_of_dice_fragments_per_dice.value
@@ -90,7 +89,7 @@ def extract_progression(state, player, options):
extra_points_in_logic = state.count("1 Point")
extra_points_in_logic += state.count("10 Points") * 10
extra_points_in_logic += state.count("100 Points") * 100
else:
else: #state is an Archipelago object, so we need state.count(..., player)
number_of_dice = (
state.count("Dice", player)
+ state.count("Dice Fragment", player) // options.number_of_dice_fragments_per_dice.value
@@ -126,10 +125,11 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
if tup in yachtdice_cache.keys():
return yachtdice_cache[tup]
#sort categories because for the step multiplier, you will want low-scorig categories first
#sort categories because for the step multiplier, you will want low-scoring categories first
categories.sort(key=lambda category: category.mean_score(num_dice, num_rolls))
#function to add two discrete distribution.
#defaultdict is a dict where you don't need to check if a id is present, you can just use += (lot faster)
def add_distributions(dist1, dist2):
combined_dist = defaultdict(float)
for val1, prob1 in dist1.items():
@@ -138,7 +138,7 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
return dict(combined_dist)
#function to take the maximum of "times" i.i.d. dist1.
#I have tried using defaultdict but this made it slower.
#(I have tried using defaultdict here too but this made it slower.)
def max_dist(dist1, mults):
new_dist = {0: 1}
for mult in mults:
@@ -172,7 +172,9 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
# Return the first value if percentile is lower than all probabilities
return prev_val if prev_val is not None else sorted_values[0]
#parameters for logic.
#perc_return is, per difficulty, the percentages of total score it returns (it averages out the values)
#diff_divide determines how many shots the logic gets per category. Lower = more shots.
perc_return = [[0], [0.1, 0.5], [0.3, 0.7], [0.55, 0.85], [0.85, 0.95]][diff]
diff_divide = [0, 9, 7, 3, 2][diff]
@@ -188,10 +190,10 @@ def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mu
dist[key] /= 100000
cat_mult = 2 ** (categories[j].quantity-1)
max_tries = j // diff_divide
mults = [(1 + fixed_mult + step_mult * ii) * cat_mult for ii in range(max(0,j - max_tries), j+1)]
#for higher difficulties, the simulation gets multiple tries for categories.
max_tries = j // diff_divide
mults = [(1 + fixed_mult + step_mult * ii) * cat_mult for ii in range(max(0,j - max_tries), j+1)]
dist = max_dist(dist, mults)
total_dist = add_distributions(total_dist, dist)

View File

@@ -40,7 +40,7 @@ class YachtDiceWorld(World):
item_name_groups = item_groups
ap_world_version = "2.0.3"
ap_world_version = "2.0.4"
def _get_yachtdice_data(self):
return {
@@ -51,7 +51,8 @@ class YachtDiceWorld(World):
"race": self.multiworld.is_race,
}
def generate_early(self):
#In generate early, we fill the item-pool, then determine the number of locations, and add filler items.
def generate_early(self):
self.itempool = []
self.precollected = []
@@ -72,8 +73,6 @@ class YachtDiceWorld(World):
if plando_setting.get("from_pool", False) is False:
self.extra_plando_items += sum(value for value in plando_setting["items"].values())
# Create a list with the specified number of 1s
num_ones = self.options.alternative_categories.value
categorylist = [1] * num_ones + [0] * (16 - num_ones)
@@ -81,8 +80,9 @@ class YachtDiceWorld(World):
# Shuffle the list to randomize the order
self.multiworld.random.shuffle(categorylist)
#A list of all possible categories.
#Every entry in the list has two categories, one 'default' category and one 'alt'.
#You get either of the two for every entry, so a total of 16 unique categories.
all_categories = [
["Category Choice", "Category Double Threes and Fours"],
["Category Inverse Choice", "Category Quadruple Ones and Twos"],
@@ -135,16 +135,20 @@ class YachtDiceWorld(World):
already_items = len(self.itempool) + self.extra_plando_items
#Yacht Dice needs extra filler items so it doesn't get stuck in generation.
#For now, we calculate the number of extra items we'll need later.
if self.options.minimize_extra_items.value:
extraPercentage = max(0.1, 0.8 - self.multiworld.players / 10)
else:
extraPercentage = 0.7
extra_locations_needed = max(10, math.ceil(already_items * extraPercentage))
#max score is the value of the last check. Goal score is the score needed to 'finish' the game
self.max_score = self.options.score_for_last_check.value
self.goal_score = min(self.max_score, self.options.score_for_goal.value)
#Yacht Dice adds items into the pool until a score of at least 1000 is reached.
#the yaml contains weights, which determine how likely it is that specific items get added.
#If all weights are 0, some of them will be made to be non-zero later.
weights = [
self.options.weight_of_dice.value,
self.options.weight_of_roll.value,
@@ -167,19 +171,22 @@ class YachtDiceWorld(World):
extra_points_added = 0
multipliers_added = 0
#Keep adding items until a score of 1000 is in logic
while dice_simulation(self.itempool + self.precollected, "state_is_a_list", self.options) < 1000:
all_items = self.itempool + self.precollected
dice_fragments_in_pool = all_items.count("Dice") * frags_per_dice + all_items.count("Dice Fragment")
if dice_fragments_in_pool + 1 >= 9 * frags_per_dice:
weights[0] = 0 #cannot have 9 dice
weights[0] = 0 #don't allow >=9 dice
roll_fragments_in_pool = all_items.count("Roll") * frags_per_roll + all_items.count("Roll Fragment")
if roll_fragments_in_pool + 1 >= 6 * frags_per_roll:
weights[1] = 0 # cannot have 6 rolls
weights[1] = 0 # don't allow >= 6 rolls
#Don't allow too many multipliers
if multipliers_added > 50:
weights[2] = 0
weights[3] = 0
#Don't allow too many extra points
if extra_points_added > 300:
weights[5] = 0
@@ -191,8 +198,8 @@ class YachtDiceWorld(World):
if extra_points_added <= 300:
weights[5] = 1
#Next, add the appropriate item. We'll slightly alter weights to avoid too many of the same item
which_item_to_add = self.multiworld.random.choices([0,1,2,3,4,5], weights = weights)[0]
if which_item_to_add == 0:
if frags_per_dice == 1:
self.itempool += ["Dice"]
@@ -214,7 +221,6 @@ class YachtDiceWorld(World):
weights[3] /= 1.1
multipliers_added += 1
elif which_item_to_add == 4:
#increase chances of "free-score categories"
cat_weights = [2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
self.itempool += self.multiworld.random.choices(possible_categories, weights = cat_weights)
weights[4] /= 1.1
@@ -247,15 +253,14 @@ class YachtDiceWorld(World):
else:
raise Exception("Invalid index when adding new items in Yacht Dice")
#count the number of locations in the game. extra_plando_items is set in generate_early
#and counts number of plando items *not* from pool.
#count the number of locations in the game.
already_items = len(self.itempool) + self.extra_plando_items + 1 #+1 because of Victory item
extra_locations_needed += (already_items - 70) // 20
#We need to add more filler/useful items if there are many items in the pool to guarantee succesful generation
extra_locations_needed += (already_items - 45) // 15
self.number_of_locations = already_items + extra_locations_needed
# From here, we will count the number of items in the self.itempool, and add items to the pool,
# From here, we will count the number of items in the self.itempool, and add usuful/filler items to the pool,
# making sure not to exceed the number of locations.
#first, we flood the entire pool with extra points (useful), if that setting is chosen.
@@ -281,7 +286,7 @@ class YachtDiceWorld(World):
if(self.number_of_locations - already_items >= 10):
self.itempool += ["Story Chapter"] * 10
#add some extra points if there is still room
#add some more extra points if there is still room
if self.options.add_bonus_points.value == 2:
already_items = len(self.itempool) + self.extra_plando_items + 1
self.itempool += ["Bonus Point"] * min(self.number_of_locations - already_items, 10)
@@ -299,7 +304,6 @@ class YachtDiceWorld(World):
#probability of Good and Bad rng, based on difficulty for fun :)
p = 1.1 - 0.25 * self.options.game_difficulty.value
already_items = len(self.itempool) + self.extra_plando_items + 1
self.itempool += self.multiworld.random.choices(
["Good RNG", "Bad RNG"],
@@ -313,15 +317,16 @@ class YachtDiceWorld(World):
raise Exception(f"[Yacht Dice] Number in self.itempool is not number of locations "
f"{already_items} {self.number_of_locations}.")
#add precollected items using push_precollected. Items in self.itempool get created in create_items
for item in self.precollected:
self.multiworld.push_precollected(self.create_item(item))
def create_items(self):
#convert strings to actual items
itempoolO = [item for item in map(lambda name: self.create_item(name), self.itempool)]
itempool_created = [item for item in map(lambda name: self.create_item(name), self.itempool)]
#and add them to the itempool
for item in itempoolO:
for item in itempool_created:
self.multiworld.itempool += [item]
def create_regions(self):
@@ -358,11 +363,6 @@ class YachtDiceWorld(World):
set_yacht_rules(self.multiworld, self.player, self.options)
set_yacht_completion_rules(self.multiworld, self.player)
maxScoreWithItems = dice_simulation(self.multiworld.get_all_state(False), self.player, self.options)
if self.goal_score > maxScoreWithItems:
raise Exception("In Yacht Dice, with all items in the pool, it is impossible to get to the goal.")
def pre_fill(self):
#in the pre_fill, make sure one dice and one roll is early, so that you will have 2 dice and 2 rolls soon
self.multiworld.early_items[self.player]["Dice"] = 1
@@ -370,9 +370,7 @@ class YachtDiceWorld(World):
def fill_slot_data(self):
#make slot data, which consists of yachtdice_data, options, and some other variables.
yacht_dice_data = self._get_yachtdice_data()
yacht_dice_options = self.options.as_dict(
"game_difficulty",
"score_for_last_check",
@@ -394,9 +392,7 @@ class YachtDiceWorld(World):
"which_story",
"allow_manual_input"
)
slot_data = {**yacht_dice_data, **yacht_dice_options} #combine the two
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["ap_world_version"] = self.ap_world_version