Skip to content

Commit

Permalink
Big update regarding logic
Browse files Browse the repository at this point in the history
Variable logic score now works.
Fixed global variables, removed all of them
Difficulty levels and corresponding functions
  • Loading branch information
spinerak authored Apr 5, 2024
1 parent 4156d13 commit 96528d7
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 41 deletions.
21 changes: 15 additions & 6 deletions yachtdice/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class numberOfExtraDice(Range):
class numberOfExtraRolls(Range):
"""Total number of extra rolls you can add to your collection."""
display_name = "Number of extra rolls"
range_start = 4
range_start = 1
range_end = 7
default = 4

Expand All @@ -31,12 +31,21 @@ class numberRollFragmentsPerRoll(Range):
default = 4


class gameDifficulty(Range):
"""Difficulty. Higher is harder. Percentage of games that fail."""
class gameDifficulty(Choice):
"""
Difficulty. This setting determines what scores you should be able to achieve given your current items.
Easy: for beginners. No luck required, just roll the dice and have fun.
Medium: intended difficulty. If you play smart, you'll finish the game without any trouble.
Hard: you will need to play smart and have a bit of luck as well. Make sure you understand the score multiplier mechanic!
Extreme: you will need to play smart, and possibly need a lot of luck.
"""
display_name = "Game difficulty"
range_start = 1
range_end = 100
default = 85
option_easy = 1
option_medium = 2
option_hard = 3
option_extreme = 4

default = 2

# class startingLoadOut(Choice):
# """
Expand Down
44 changes: 24 additions & 20 deletions yachtdice/Rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@



PERCENTAGE_REQUIRED = 10100 #temporary value that gets overwritten
ITERATIONS_PER_GAME = 100


class Category:
def __init__(self, name):
Expand All @@ -34,22 +33,22 @@ def simulateRolls(self, nbDice, nbRolls):
random.choices(list(yacht_weights[self.name, nbDice, nbRolls].keys()),
yacht_weights[self.name, nbDice, nbRolls].values(), k=1)[0]

def setDifficulty(num):
global PERCENTAGE_REQUIRED
PERCENTAGE_REQUIRED = 100 - num



cache = {}
# count_cache = 0
# count_not_cache = 0
def canReachScore(state: CollectionState, player, scoretarget: int, options):
if scoretarget < 10:
def canReachScore(state: CollectionState, player, scoretarget: int, options, seed, it_game, perc_req):
if scoretarget <= 10:
return True
# global count_cache
# global count_not_cache

[c, r, d, m] = extractProgression(state, player, options)
thisState = [*sorted([a.name for a in c]), r, d, m]



if tuple(thisState) in cache.keys():
# index = list(cache.keys()).index(tuple(thisState))
Expand All @@ -60,25 +59,30 @@ def canReachScore(state: CollectionState, player, scoretarget: int, options):
# print(f"{count_cache} {count_not_cache}")
else:
[a1, a2, a3, a4] = extractProgression(state, player, options)
scores = diceSimulation([a1, a2, a3, a4])
scores = diceSimulation(seed, [a1, a2, a3, a4], it_game)
state = [*sorted([a.name for a in a1]), a2, a3, a4]
cache[tuple(state)] = scores
# count_not_cache += 1
# print(f"{count_cache} {count_not_cache}")

# if scoretarget == 500:
# print(verifyAccessibility(scoretarget))
return verifyAccessibility(scores, scoretarget)
return verifyAccessibility(scores, scoretarget, it_game, perc_req)

def verifyAccessibility(scores, score):
global PERCENTAGE_REQUIRED
def verifyAccessibility(scores, score, it_game, perc_req):

P = perc_req
if score < 50:
P = min(P,2)
elif score < 100:
P = min(P,6)

wins = len(list(filter(lambda s:s>=score, scores)))
if wins == 0:
return False


return wins / ITERATIONS_PER_GAME >= PERCENTAGE_REQUIRED / 100
return wins / it_game >= P / 100

def extractProgression(state, player, options):
number_of_dice = state.count("Dice", player) + state.count("Dice Fragment", player) // options.number_of_dice_fragments_per_dice.value
Expand Down Expand Up @@ -123,17 +127,17 @@ def extractProgression(state, player, options):
if state.has("Category Yacht", player, 1):
categories.append(Category("Yacht"))

return [categories, number_of_rerolls, number_of_dice, score_mult]
return [categories, number_of_dice, number_of_rerolls, score_mult]

def diceSimulation(ST):
categories, nbRolls, nbDice, multiplier = ST
def diceSimulation(seed, ST, it_game):
categories, nbDice, nbRolls, multiplier = ST

random.seed(42)

scores = []

categories.sort(key=lambda category: category.meanScore(nbDice, nbRolls))
for i in range(ITERATIONS_PER_GAME):
for i in range(it_game):
total = 0
for j in range(len(categories)):
roll = int(categories[j].simulateRolls(nbDice, nbRolls) * (1 + j * multiplier))
Expand All @@ -143,7 +147,7 @@ def diceSimulation(ST):
return scores

# Sets rules on entrances and advancements that are always applied
def set_rules(world: MultiWorld, player: int, options, goal_score):
def set_rules(world: MultiWorld, player: int, options, goal_score, seed, it_game, perc_req):

num_locs = 140

Expand All @@ -162,15 +166,15 @@ def set_rules(world: MultiWorld, player: int, options, goal_score):
lambda state,
curscore=curscore,
player=player:
canReachScore(state, player, curscore, options))
canReachScore(state, player, curscore, options, seed, it_game, perc_req))

set_rule(world.get_location(f"{goal_score} score", player),
lambda state,
player=player:
canReachScore(state, player, goal_score, options))
canReachScore(state, player, goal_score, options, seed, it_game, perc_req))



# Sets rules on completion condition
def set_completion_rules(world: MultiWorld, player: int, options, goal_score):
def set_completion_rules(world: MultiWorld, player: int):
world.completion_condition[player] = lambda state: state.has("Victory", player)
59 changes: 44 additions & 15 deletions yachtdice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from .Items import YachtDiceItem, item_table
from .Locations import YachtDiceLocation, all_locations, ini_locations, AdvData
from .Options import yachtdice_options
from .Rules import set_rules, set_completion_rules, diceSimulation, Category, setDifficulty
from .Rules import set_rules, set_completion_rules, diceSimulation, Category
from ..AutoWorld import World, WebWorld

client_version = 345
Expand All @@ -20,6 +20,9 @@ class YachtDiceWorld(World):
# web = ChecksFinderWeb()


PERCENTAGE_REQUIRED = 100000
NUMBER_OF_ITERATIONS = 100


item_name_to_id = {name: data.code for name, data in item_table.items()}

Expand All @@ -41,7 +44,7 @@ def _get_yachtdice_data(self):

def create_items(self):

print(f"For Yacht Dice debug purposes: here's the options {self.options} for player {self.player}\n\n")
# print(f"For Yacht Dice debug purposes: here's the options {self.options} for player {self.player}\n\n")


numDiceF = self.options.number_of_extra_dice.value
Expand Down Expand Up @@ -113,13 +116,20 @@ def create_items(self):


def set_rules(self):
set_rules(self.multiworld, self.player, self.options, self.goal_score)
set_completion_rules(self.multiworld, self.player, self.options, self.goal_score)
seed = 42
if (self.multiworld.seed_name).isdigit(): # Check if seed_name contains only digits
seed = int(self.multiworld.seed_name) % 1000
set_rules(self.multiworld, self.player, self.options, self.goal_score, seed, self.NUMBER_OF_ITERATIONS, self.PERCENTAGE_REQUIRED)
set_completion_rules(self.multiworld, self.player)

goal_score = -1

def create_regions(self):

seed = 42
if (self.multiworld.seed_name).isdigit(): # Check if seed_name contains only digits
seed = int(self.multiworld.seed_name) % 1000

categories = []

categories.append(Category("Choice"))
Expand All @@ -141,20 +151,39 @@ def create_regions(self):



scores_full_state = diceSimulation([categories,
1 + self.options.number_of_extra_dice.value,
1 + self.options.number_of_extra_rolls.value,
0.1])





game_difficulty = self.options.game_difficulty.value

dif = 50
if game_difficulty == 1:
dif = 54
elif game_difficulty == 2:
dif = 73
elif game_difficulty == 3:
dif = 95
elif game_difficulty == 4:
dif = 99
self.NUMBER_OF_ITERATIONS = 1000

self.PERCENTAGE_REQUIRED = 100 - dif

scores_full_state = diceSimulation(seed, [categories,
1 + self.options.number_of_extra_dice.value,
1 + self.options.number_of_extra_rolls.value,
0.1], self.NUMBER_OF_ITERATIONS)
scores_full_state = sorted(scores_full_state)
print(f"Here's the simulation results: {scores_full_state}")
dif = self.options.game_difficulty.value
self.goal_score = scores_full_state[int(max(0,100-(100-dif)*1.2))]
ind = max(0, min(len(scores_full_state)-1, int((dif-5) / 100 * len(scores_full_state))))
self.goal_score = scores_full_state[ind]

if dif < 60:
self.goal_score = min(self.goal_score, 700)

if self.options.game_difficulty.value < 50:
self.goal_score = int(self.goal_score * (1 - (50-self.options.game_difficulty.value)/100))

print(f"Yacht dice debug: goal score for player {self.player} is {self.goal_score} and difficulty {self.options.game_difficulty.value}")
# print(f"Yacht dice debug: goal score for player {self.player} is {self.goal_score} and difficulty {dif}")

location_table = ini_locations(self.goal_score, 140)

Expand All @@ -179,7 +208,7 @@ def create_regions(self):
connection.connect(board)
self.multiworld.regions += [menu, board]

setDifficulty(self.options.game_difficulty.value)
self.ITERATIONS_PER_GAME = 100 - dif



Expand Down

0 comments on commit 96528d7

Please sign in to comment.