@@ -550,36 +550,36 @@ def flood_items(world: MultiWorld) -> None:
550
550
break
551
551
552
552
553
- def balance_multiworld_progression (world : MultiWorld ) -> None :
553
+ def balance_multiworld_progression (multiworld : MultiWorld ) -> None :
554
554
# A system to reduce situations where players have no checks remaining, popularly known as "BK mode."
555
555
# Overall progression balancing algorithm:
556
556
# Gather up all locations in a sphere.
557
557
# Define a threshold value based on the player with the most available locations.
558
558
# If other players are below the threshold value, swap progression in this sphere into earlier spheres,
559
559
# which gives more locations available by this sphere.
560
560
balanceable_players : typing .Dict [int , float ] = {
561
- player : world .worlds [player ].options .progression_balancing / 100
562
- for player in world .player_ids
563
- if world .worlds [player ].options .progression_balancing > 0
561
+ player : multiworld .worlds [player ].options .progression_balancing / 100
562
+ for player in multiworld .player_ids
563
+ if multiworld .worlds [player ].options .progression_balancing > 0
564
564
}
565
565
if not balanceable_players :
566
566
logging .info ('Skipping multiworld progression balancing.' )
567
567
else :
568
568
logging .info (f'Balancing multiworld progression for { len (balanceable_players )} Players.' )
569
569
logging .debug (balanceable_players )
570
- state : CollectionState = CollectionState (world )
570
+ state : CollectionState = CollectionState (multiworld )
571
571
checked_locations : typing .Set [Location ] = set ()
572
- unchecked_locations : typing .Set [Location ] = set (world .get_locations ())
572
+ unchecked_locations : typing .Set [Location ] = set (multiworld .get_locations ())
573
573
574
574
total_locations_count : typing .Counter [int ] = Counter (
575
575
location .player
576
- for location in world .get_locations ()
576
+ for location in multiworld .get_locations ()
577
577
if not location .locked
578
578
)
579
579
reachable_locations_count : typing .Dict [int , int ] = {
580
580
player : 0
581
- for player in world .player_ids
582
- if total_locations_count [player ] and len (world .get_filled_locations (player )) != 0
581
+ for player in multiworld .player_ids
582
+ if total_locations_count [player ] and len (multiworld .get_filled_locations (player )) != 0
583
583
}
584
584
balanceable_players = {
585
585
player : balanceable_players [player ]
@@ -658,7 +658,7 @@ def item_percentage(player: int, num: int) -> float:
658
658
balancing_unchecked_locations .remove (location )
659
659
if not location .locked :
660
660
balancing_reachables [location .player ] += 1
661
- if world .has_beaten_game (balancing_state ) or all (
661
+ if multiworld .has_beaten_game (balancing_state ) or all (
662
662
item_percentage (player , reachables ) >= threshold_percentages [player ]
663
663
for player , reachables in balancing_reachables .items ()
664
664
if player in threshold_percentages ):
@@ -675,7 +675,7 @@ def item_percentage(player: int, num: int) -> float:
675
675
locations_to_test = unlocked_locations [player ]
676
676
items_to_test = list (candidate_items [player ])
677
677
items_to_test .sort ()
678
- world .random .shuffle (items_to_test )
678
+ multiworld .random .shuffle (items_to_test )
679
679
while items_to_test :
680
680
testing = items_to_test .pop ()
681
681
reducing_state = state .copy ()
@@ -687,42 +687,41 @@ def item_percentage(player: int, num: int) -> float:
687
687
688
688
reducing_state .sweep_for_events (locations = locations_to_test )
689
689
690
- if world .has_beaten_game (balancing_state ):
691
- if not world .has_beaten_game (reducing_state ):
690
+ if multiworld .has_beaten_game (balancing_state ):
691
+ if not multiworld .has_beaten_game (reducing_state ):
692
692
items_to_replace .append (testing )
693
693
else :
694
694
reduced_sphere = get_sphere_locations (reducing_state , locations_to_test )
695
695
p = item_percentage (player , reachable_locations_count [player ] + len (reduced_sphere ))
696
696
if p < threshold_percentages [player ]:
697
697
items_to_replace .append (testing )
698
698
699
- replaced_items = False
699
+ old_moved_item_count = moved_item_count
700
700
701
701
# sort then shuffle to maintain deterministic behaviour,
702
702
# while allowing use of set for better algorithm growth behaviour elsewhere
703
703
replacement_locations = sorted (l for l in checked_locations if not l .event and not l .locked )
704
- world .random .shuffle (replacement_locations )
704
+ multiworld .random .shuffle (replacement_locations )
705
705
items_to_replace .sort ()
706
- world .random .shuffle (items_to_replace )
706
+ multiworld .random .shuffle (items_to_replace )
707
707
708
708
# Start swapping items. Since we swap into earlier spheres, no need for accessibility checks.
709
709
while replacement_locations and items_to_replace :
710
710
old_location = items_to_replace .pop ()
711
- for new_location in replacement_locations :
711
+ for i , new_location in enumerate ( replacement_locations ) :
712
712
if new_location .can_fill (state , old_location .item , False ) and \
713
713
old_location .can_fill (state , new_location .item , False ):
714
- replacement_locations .remove ( new_location )
714
+ replacement_locations .pop ( i )
715
715
swap_location_item (old_location , new_location )
716
716
logging .debug (f"Progression balancing moved { new_location .item } to { new_location } , "
717
717
f"displacing { old_location .item } into { old_location } " )
718
718
moved_item_count += 1
719
719
state .collect (new_location .item , True , new_location )
720
- replaced_items = True
721
720
break
722
721
else :
723
722
logging .warning (f"Could not Progression Balance { old_location .item } " )
724
723
725
- if replaced_items :
724
+ if old_moved_item_count < moved_item_count :
726
725
logging .debug (f"Moved { moved_item_count } items so far\n " )
727
726
unlocked = {fresh for player in balancing_players for fresh in unlocked_locations [player ]}
728
727
for location in get_sphere_locations (state , unlocked ):
@@ -736,7 +735,7 @@ def item_percentage(player: int, num: int) -> float:
736
735
state .collect (location .item , True , location )
737
736
checked_locations |= sphere_locations
738
737
739
- if world .has_beaten_game (state ):
738
+ if multiworld .has_beaten_game (state ):
740
739
break
741
740
elif not sphere_locations :
742
741
logging .warning ("Progression Balancing ran out of paths." )
0 commit comments