Formatting style

This commit is contained in:
spinerak
2024-06-05 23:48:47 +02:00
parent 3da552d1d3
commit 260405469d
7 changed files with 81 additions and 80 deletions

View File

@@ -73,7 +73,7 @@ item_table = {
"100 Points": ItemData(16871244303, ItemClassification.progression)
}
ITEM_GROUPS = {
item_groups = {
"Score Multiplier": {
"Score Multiplier",
"Step Score Multiplier",

View File

@@ -15,7 +15,7 @@ class YachtDiceLocation(Location):
self.event = not address
all_locations = {}
starting_index = 16871244500 #500 more than the startin index for items
starting_index = 16871244500 #500 more than the starting index for items
#Function that is called when this file is loaded, which loads in ALL possible locations, score 1 to 1000
def all_locations_fun(max_score):

View File

@@ -5,8 +5,8 @@ class gameDifficulty(Choice):
"""
Difficulty. This setting determines how difficult the scores are to achieve.
Easy: for beginners. No luck required, just roll the dice and have fun. Lower final goal.
Medium: intended difficulty. If you play smart, you'll finish the game without any trouble.
Hard: you'll need to play smart and be lucky.
Medium: intended difficulty. If you play smart, you will finish the game without any trouble.
Hard: you will need to play smart and be lucky.
Extreme: really hard mode, which requires many brain wrinkles and insane luck. NOT RECOMMENDED FOR MULTIWORLDS.
"""
display_name = "Game difficulty"
@@ -58,7 +58,7 @@ class numberDiceFragmentsPerDice(Range):
Dice can be split into fragments, gathering enough will give you an extra dice.
You start with one dice, and there will always be one full dice in the pool.
The other dice are split into fragments, according to this setting.
Setting this to 1 fragment per dice just puts 'Dice' objects in the pool.
Setting this to 1 fragment per dice just puts "Dice" objects in the pool.
"""
display_name = "Number of dice fragments per dice"
range_start = 1
@@ -70,7 +70,7 @@ class numberRollFragmentsPerRoll(Range):
Rolls can be split into fragments, gathering enough will give you an extra roll.
You start with one roll, and there will always be one full roll in the pool.
The other three rolls are split into fragments, according to this setting.
Setting this to 1 fragment per roll just puts 'Roll' objects in the pool.
Setting this to 1 fragment per roll just puts "Roll" objects in the pool.
"""
display_name = "Number of roll fragments per roll"
range_start = 1
@@ -110,7 +110,7 @@ class chanceOfDice(Range):
class chanceOfRoll(Range):
"""
With more rolls, you'll be able to reach higher scores.
With more rolls, you will be able to reach higher scores.
"""
display_name = "Weight of adding Roll"
range_start = 0
@@ -187,7 +187,7 @@ class addExtraPoints(Choice):
all_of_it: fill all locations with extra points
sure: put some bonus points in
never: don't put any bonus points
never: do not put any bonus points
"""
display_name = "Extra bonus in the pool"
option_all_of_it = 1
@@ -199,11 +199,11 @@ class addStoryChapters(Choice):
"""
Yacht Dice typically has space for more items.
If there is space, would you like story chapters shuffled in the item pool?
Note: if you have extra points on "all_of_it", there won't be story chapters.
Note: if you have extra points on "all_of_it", there will not be story chapters.
all_of_it: fill all locations with story chapters
sure: if there is space left, put in 10 story chapters.
never: don't put any story chapters, I don't like reading (but I'm glad you're reading THIS!)
never: do not put any story chapters, I do not like reading (but I am glad you are reading THIS!)
"""
display_name = "Extra story chapters in the pool"
option_all_of_it = 1

View File

@@ -56,17 +56,17 @@ class Category:
self.quantity = quantity #how many times you have the category
#return mean score of a category
def meanScore(self, nbDice, nbRolls):
if nbDice == 0 or nbRolls == 0:
def mean_score(self, num_dice, num_rolls):
if num_dice == 0 or num_rolls == 0:
return 0
meanScore = 0
for key in yacht_weights[self.name, min(8,nbDice), min(8,nbRolls)]:
meanScore += key*yacht_weights[self.name, min(8,nbDice), min(8,nbRolls)][key]/100000
return meanScore * self.quantity
mean_score = 0
for key in yacht_weights[self.name, min(8,num_dice), min(8,num_rolls)]:
mean_score += key*yacht_weights[self.name, min(8,num_dice), min(8,num_rolls)][key]/100000
return mean_score * self.quantity
def extractProgression(state, player, options):
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.
@@ -118,16 +118,16 @@ def extractProgression(state, player, options):
yachtdice_cache = {}
#Function that returns the feasible score in logic based on items obtained.
def diceSimulationStrings(categories, nbDice, nbRolls, fixed_mult, step_mult, diff):
def dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mult, diff):
tup = tuple([tuple(sorted([c.name+str(c.quantity) for c in categories])),
nbDice, nbRolls, fixed_mult, step_mult, diff]) #identifier
num_dice, num_rolls, fixed_mult, step_mult, diff]) #identifier
#if already computed, return the result
if tup in yachtdice_cache.keys():
return yachtdice_cache[tup]
#sort categories because for the step multiplier, you will want low-scorig categories first
categories.sort(key=lambda category: category.meanScore(nbDice, nbRolls))
categories.sort(key=lambda category: category.mean_score(num_dice, num_rolls))
#function to add two discrete distribution.
def add_distributions(dist1, dist2):
@@ -137,8 +137,8 @@ def diceSimulationStrings(categories, nbDice, nbRolls, fixed_mult, step_mult, di
combined_dist[val1 + val2] += prob1 * prob2
return dict(combined_dist)
#function to take the maximum of 'times' i.i.d. dist1.
#I've tried using defaultdict but this made it slower.
#function to take the maximum of "times" i.i.d. dist1.
#I have tried using defaultdict but this made it slower.
def max_dist(dist1, mults):
new_dist = {0: 1}
for mult in mults:
@@ -173,23 +173,22 @@ def diceSimulationStrings(categories, nbDice, nbRolls, fixed_mult, step_mult, di
return prev_val if prev_val is not None else sorted_values[0]
percReturn = [[0], [0.1, 0.5], [0.3, 0.7], [0.55, 0.85], [0.85, 0.95]][diff]
diffDivide = [0, 9, 7, 3, 2][diff]
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]
#calculate total distribution
total_dist = {0: 1}
for j in range(len(categories)):
if nbDice == 0 or nbRolls == 0:
if num_dice == 0 or num_rolls == 0:
dist = {0: 100000}
else:
dist = yacht_weights[categories[j].name, min(8,nbDice), min(8,nbRolls)].copy()
dist = yacht_weights[categories[j].name, min(8,num_dice), min(8,num_rolls)].copy()
for key in dist.keys():
dist[key] /= 100000
cat_mult = 2 ** (categories[j].quantity-1)
max_tries = j // diffDivide
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.
@@ -198,13 +197,13 @@ def diceSimulationStrings(categories, nbDice, nbRolls, fixed_mult, step_mult, di
total_dist = add_distributions(total_dist, dist)
#save result into the cache, then return it
yachtdice_cache[tup] = math.floor(sum([percentile_distribution(total_dist, perc) for perc in percReturn]) / len(percReturn))
yachtdice_cache[tup] = math.floor(sum([percentile_distribution(total_dist, perc) for perc in perc_return]) / len(perc_return))
return yachtdice_cache[tup]
# Returns the feasible score that one can reach with the current state, options and difficulty.
def diceSimulation(state, player, options):
categories, nbDice, nbRolls, fixed_mult, step_mult, expoints = extractProgression(state, player, options)
return diceSimulationStrings(categories, nbDice, nbRolls, fixed_mult, step_mult,
def dice_simulation(state, player, options):
categories, num_dice, num_rolls, fixed_mult, step_mult, expoints = extract_progression(state, player, options)
return dice_simulation_strings(categories, num_dice, num_rolls, fixed_mult, step_mult,
options.game_difficulty.value) + expoints
# Sets rules on entrances and advancements that are always applied
@@ -214,7 +213,7 @@ def set_yacht_rules(world: MultiWorld, player: int, options):
lambda state,
curscore=l.yacht_dice_score,
player=player:
diceSimulation(state, player, options) >= curscore)
dice_simulation(state, player, options) >= curscore)
# Sets rules on completion condition
def set_yacht_completion_rules(world: MultiWorld, player: int):

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,14 @@
from BaseClasses import Region, Entrance, Item, Tutorial
from .Items import YachtDiceItem, item_table, ITEM_GROUPS
from .Locations import YachtDiceLocation, all_locations, ini_locations
from .Options import YachtDiceOptions
from .Rules import set_yacht_rules, set_yacht_completion_rules, diceSimulation
from ..AutoWorld import World, WebWorld
import math
import logging
from BaseClasses import Region, Entrance, Item, Tutorial
from .Items import YachtDiceItem, item_table, item_groups
from .Locations import YachtDiceLocation, all_locations, ini_locations
from .Options import YachtDiceOptions
from .Rules import set_yacht_rules, set_yacht_completion_rules, dice_simulation
from ..AutoWorld import World, WebWorld
class YachtDiceWeb(WebWorld):
tutorials = [Tutorial(
"Multiworld Setup Guide",
@@ -24,7 +26,7 @@ class YachtDiceWorld(World):
where you cast your dice to chart a course for high scores,
unlocking valuable treasures along the way.
Discover more dice, extra rolls, multipliers,
and unlockable categories to navigate the game's depths.
and unlockable categories to navigate the depths of the game.
Roll your way to victory by reaching the target score!
"""
game: str = "Yacht Dice"
@@ -36,7 +38,7 @@ class YachtDiceWorld(World):
location_name_to_id = {name: data.id for name, data in all_locations.items()}
item_name_groups = ITEM_GROUPS
item_name_groups = item_groups
ap_world_version = "2.0.2"
@@ -56,12 +58,12 @@ class YachtDiceWorld(World):
#number of dice and rolls in the pull
ind_dice_rolls = self.options.minimal_number_of_dice_and_rolls.value
numDice = [0, 2, 5, 5, 6, 7, 8][ind_dice_rolls]
numRolls = [0, 2, 3, 5, 4, 3, 2][ind_dice_rolls]
num_of_dice = [0, 2, 5, 5, 6, 7, 8][ind_dice_rolls]
num_of_rolls = [0, 2, 3, 5, 4, 3, 2][ind_dice_rolls]
#amount of dice and roll fragments needed to get a dice or roll
amDiceF = self.options.number_of_dice_fragments_per_dice.value
amRollsF = self.options.number_of_roll_fragments_per_roll.value
frags_per_dice = self.options.number_of_dice_fragments_per_dice.value
frags_per_roll = self.options.number_of_roll_fragments_per_roll.value
#count number of plando items not from pool, we need extra locations for them
self.extra_plando_items = 0
@@ -117,18 +119,18 @@ class YachtDiceWorld(World):
self.precollected += ["Dice"]
#if one fragment per dice, just add "Dice" objects
if amDiceF == 1:
self.itempool += ["Dice"] * (numDice-1) #minus one because one is in start inventory
if frags_per_dice == 1:
self.itempool += ["Dice"] * (num_of_dice-1) #minus one because one is in start inventory
else:
self.itempool += ["Dice"] #always add a full dice to make generation easier (will be 'early')
self.itempool += ["Dice Fragment"] * (amDiceF * (numDice-2))
self.itempool += ["Dice"] #always add a full dice to make generation easier (will be early)
self.itempool += ["Dice Fragment"] * (frags_per_dice * (num_of_dice-2))
#if one fragment per roll, just add "Roll" objects
if amRollsF == 1:
self.itempool += ["Roll"] * (numRolls-1) #minus one because one is in start inventory
if frags_per_roll == 1:
self.itempool += ["Roll"] * (num_of_rolls-1) #minus one because one is in start inventory
else:
self.itempool += ["Roll"] #always add a full roll to make generation easier (will be 'early')
self.itempool += ["Roll Fragment"] * (amRollsF * (numRolls-2))
self.itempool += ["Roll"] #always add a full roll to make generation easier (will be early)
self.itempool += ["Roll Fragment"] * (frags_per_roll * (num_of_rolls-2))
already_items = len(self.itempool) + self.extra_plando_items
@@ -138,7 +140,7 @@ class YachtDiceWorld(World):
else:
extraPercentage = 0.7
extraLocationsNeeded = max(10, math.ceil(already_items * extraPercentage))
extra_locations_needed = max(10, math.ceil(already_items * extraPercentage))
self.max_score = self.options.score_for_last_check.value
self.goal_score = min(self.max_score, self.options.score_for_goal.value)
@@ -153,25 +155,25 @@ class YachtDiceWorld(World):
]
#if the player wants extra rolls or dice, fill the pool with fragments until close to an extra roll/dice
if weights[0] > 0 and amDiceF > 1:
self.itempool += ["Dice Fragment"] * (amDiceF - 1)
if weights[1] > 0 and amRollsF > 1:
self.itempool += ["Roll Fragment"] * (amRollsF - 1)
if weights[0] > 0 and frags_per_dice > 1:
self.itempool += ["Dice Fragment"] * (frags_per_dice - 1)
if weights[1] > 0 and frags_per_roll > 1:
self.itempool += ["Roll Fragment"] * (frags_per_roll - 1)
#calibrate the weights, since the impact of each of the items is different
weights[0] = weights[0] / 5 * amDiceF
weights[1] = weights[1] / 5 * amRollsF
weights[0] = weights[0] / 5 * frags_per_dice
weights[1] = weights[1] / 5 * frags_per_roll
extraPointsAdded = 0
while diceSimulation(self.itempool + self.precollected, "state_is_a_list", self.options) < 1000:
allitems = self.itempool + self.precollected
dice_fragments_in_pool = allitems.count("Dice") * amDiceF + allitems.count("Dice Fragment")
if dice_fragments_in_pool + 1 >= 9 * amDiceF:
weights[0] = 0 #can't have 9 dice
roll_fragments_in_pool = allitems.count("Roll") * amRollsF + allitems.count("Roll Fragment")
if roll_fragments_in_pool + 1 >= 6 * amRollsF:
weights[1] = 0 # can't have 6 rolls
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
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
if extraPointsAdded > 300:
weights[5] = 0
@@ -185,17 +187,17 @@ class YachtDiceWorld(World):
which_item_to_add = self.multiworld.random.choices([0,1,2,3,4,5], weights = weights)[0]
if which_item_to_add == 0:
if amDiceF == 1:
if frags_per_dice == 1:
self.itempool += ["Dice"]
else:
self.itempool += ["Dice Fragment"]
weights[0] /= (1 + amDiceF)
weights[0] /= (1 + frags_per_dice)
elif which_item_to_add == 1:
if amRollsF == 1:
if frags_per_roll == 1:
self.itempool += ["Roll"]
else:
self.itempool += ["Roll Fragment"]
weights[1] /= (1 + amRollsF)
weights[1] /= (1 + frags_per_roll)
elif which_item_to_add == 2:
self.itempool += ["Fixed Score Multiplier"]
weights[2] /= 1.05
@@ -240,9 +242,9 @@ class YachtDiceWorld(World):
#and counts number of plando items *not* from pool.
already_items = len(self.itempool) + self.extra_plando_items + 1 #+1 because of Victory item
self.number_of_locations = already_items + extraLocationsNeeded
self.number_of_locations = already_items + extra_locations_needed
# From here, we'll 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 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.
@@ -282,7 +284,7 @@ class YachtDiceWorld(World):
self.itempool += ["Fun Fact"] * min(self.number_of_locations - already_items, 5)
#finally, add some "Good RNG" and "Bad RNG" items to complete the item pool
#these items are filler and don't do anything.
#these items are filler and do not do anything.
#probability of Good and Bad rng, based on difficulty for fun :)
p = 1.1 - 0.25 * self.options.game_difficulty.value
@@ -294,7 +296,7 @@ class YachtDiceWorld(World):
k=self.number_of_locations - already_items
)
#we're done adding items. Now because of the last step, number of items should be number of locations
#we are done adding items. Now because of the last step, number of items should be number of locations
already_items = len(self.itempool) + self.extra_plando_items + 1
if already_items != self.number_of_locations:
raise Exception(f"[Yacht Dice] Number in self.itempool is not number of locations "
@@ -345,13 +347,13 @@ class YachtDiceWorld(World):
set_yacht_rules(self.multiworld, self.player, self.options)
set_yacht_completion_rules(self.multiworld, self.player)
maxScoreWithItems = diceSimulation(self.multiworld.get_all_state(False), self.player, self.options)
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'll have 2 dice and 2 rolls soon
#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
self.multiworld.early_items[self.player]["Roll"] = 1

View File

@@ -10,7 +10,7 @@ Open the Yacht Dice website. There are two options:
- Download the latest release from [Yacht Dice Releases](https://github.com/spinerak/ArchipelagoYachtDice/releases) and unzip the Website.zip. Then open player.html in your browser.
- Cruise over to the [Yacht Dice website](https://yacht-dice-ap.netlify.app/). This also works on mobile. If the website is not available, use the first option.
The website has an offline play option to try out the game without having to generate a game first.
Both options have an "offline" play option to try out the game without having to generate a game first.
## Play with Archipelago