TLOZ: Fix non-deterministic item pool generation (#3779)
* TLOZ: Fix non-deterministic item pool generation The way the item pool was constructed involved iterating unions of sets. Sets are unordered, so the order of iteration of these combined sets would be non-deterministic, resulting in the items in the item pool being generated in a different order with the same seed. Rather than creating unions of sets at all, the original code has been replaced with using Counter objects. As a dict subclass, Counter maintains insertion order, and its update() method makes it simple to combine the separate item dictionaries into a single dictionary with the total count of each item across each of the separate item dictionaries. Fixes #3664 - After investigating more deeply, the only differences I could find between generations of the same seed was the order of items created by TLOZ, so this patch appears to fix the non-deterministic generation issue. I did manage to reproduce the non-deterministic behaviour with just TLOZ in the end, but it was very rare. I'm not entirely sure why generating with SMZ3 specifically would cause the non-deterministic behaviour in TLOZ to be frequently present, whereas generating with other games or multiple TLOZ yamls would not. * Change import order --------- Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
This commit is contained in:
parent
474a3181c6
commit
7eda4c47f8
|
@ -1,3 +1,5 @@
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
from BaseClasses import ItemClassification
|
from BaseClasses import ItemClassification
|
||||||
from .Locations import level_locations, all_level_locations, standard_level_locations, shop_locations
|
from .Locations import level_locations, all_level_locations, standard_level_locations, shop_locations
|
||||||
from .Options import TriforceLocations, StartingPosition
|
from .Options import TriforceLocations, StartingPosition
|
||||||
|
@ -58,11 +60,11 @@ map_compass_replacements = {
|
||||||
"Small Key": 2,
|
"Small Key": 2,
|
||||||
"Five Rupees": 2
|
"Five Rupees": 2
|
||||||
}
|
}
|
||||||
basic_pool = {
|
basic_pool = Counter()
|
||||||
item: overworld_items.get(item, 0) + shop_items.get(item, 0)
|
basic_pool.update(overworld_items)
|
||||||
+ major_dungeon_items.get(item, 0) + map_compass_replacements.get(item, 0)
|
basic_pool.update(shop_items)
|
||||||
for item in set(overworld_items) | set(shop_items) | set(major_dungeon_items) | set(map_compass_replacements)
|
basic_pool.update(major_dungeon_items)
|
||||||
}
|
basic_pool.update(map_compass_replacements)
|
||||||
|
|
||||||
starting_weapons = ["Sword", "White Sword", "Magical Sword", "Magical Rod", "Red Candle"]
|
starting_weapons = ["Sword", "White Sword", "Magical Sword", "Magical Rod", "Red Candle"]
|
||||||
guaranteed_shop_items = ["Small Key", "Bomb", "Water of Life (Red)", "Arrow"]
|
guaranteed_shop_items = ["Small Key", "Bomb", "Water of Life (Red)", "Arrow"]
|
||||||
|
@ -135,10 +137,10 @@ def get_pool_core(world):
|
||||||
# Finish Pool
|
# Finish Pool
|
||||||
final_pool = basic_pool
|
final_pool = basic_pool
|
||||||
if world.options.ExpandedPool:
|
if world.options.ExpandedPool:
|
||||||
final_pool = {
|
final_pool = Counter()
|
||||||
item: basic_pool.get(item, 0) + minor_items.get(item, 0) + take_any_items.get(item, 0)
|
final_pool.update(basic_pool)
|
||||||
for item in set(basic_pool) | set(minor_items) | set(take_any_items)
|
final_pool.update(minor_items)
|
||||||
}
|
final_pool.update(take_any_items)
|
||||||
final_pool["Five Rupees"] -= 1
|
final_pool["Five Rupees"] -= 1
|
||||||
for item in final_pool.keys():
|
for item in final_pool.keys():
|
||||||
for i in range(0, final_pool[item]):
|
for i in range(0, final_pool[item]):
|
||||||
|
|
Loading…
Reference in New Issue