2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								import  random  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  logging  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  BaseClasses  import  CollectionState  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								class  FillError ( RuntimeError ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-04 14:23:57 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								def  distribute_items_cutoff ( world ,  cutoffrate = 0.33 ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get list of locations to fill in 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    fill_locations  =  world . get_unfilled_locations ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( fill_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get items to distribute 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( world . itempool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    itempool  =  world . itempool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    total_advancement_items  =  len ( [ item  for  item  in  itempool  if  item . advancement ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    placed_advancement_items  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    progress_done  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    advancement_placed  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # sweep once to pick up preplaced items 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    world . state . sweep_for_events ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  itempool  and  fill_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        candidate_item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  item  in  itempool : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  advancement_placed  or  ( progress_done  and  ( item . advancement  or  item . priority ) ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  item . advancement : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                candidate_item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . unlocks_new_location ( item ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    placed_advancement_items  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  item_to_place  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # check if we can reach all locations and that is why we find no new locations to place 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  not  progress_done  and  len ( world . get_reachable_locations ( ) )  ==  len ( world . get_locations ( ) ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                progress_done  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # check if we have now placed all advancement items 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  progress_done : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                advancement_placed  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # we might be in a situation where all new locations require multiple items to reach. If that is the case, just place any advancement item we've found and continue trying 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  candidate_item_to_place  is  not  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  candidate_item_to_place 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                placed_advancement_items  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # we placed all available progress items. Maybe the game can be beaten anyway? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . can_beat_game ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logging . getLogger ( ' ' ) . warning ( ' Not all locations reachable. Game beatable anyway. ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    progress_done  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    continue 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                raise  FillError ( ' No more progress items left to place. ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        spot_to_fill  =  None 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-17 00:25:46 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for  location  in  fill_locations  if  placed_advancement_items  /  total_advancement_items  <  cutoffrate  else  reversed ( fill_locations ) : 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  location . can_fill ( world . state ,  item_to_place ) : 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                spot_to_fill  =  location 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  spot_to_fill  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # we filled all reachable spots. Maybe the game can be beaten anyway? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  world . can_beat_game ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                logging . getLogger ( ' ' ) . warning ( ' Not all items placed. Game beatable anyway. ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            raise  FillError ( ' No more spots to place  %s '  %  item_to_place ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        world . push_item ( spot_to_fill ,  item_to_place ,  True ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        itempool . remove ( item_to_place ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        fill_locations . remove ( spot_to_fill ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-17 00:25:46 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logging . getLogger ( ' ' ) . debug ( ' Unplaced items:  %s  - Unfilled Locations:  %s ' ,  [ item . name  for  item  in  itempool ] ,  [ location . name  for  location  in  fill_locations ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  distribute_items_staleness ( world ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get list of locations to fill in 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    fill_locations  =  world . get_unfilled_locations ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( fill_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get items to distribute 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( world . itempool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    itempool  =  world . itempool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    progress_done  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    advancement_placed  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # sweep once to pick up preplaced items 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    world . state . sweep_for_events ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  itempool  and  fill_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        candidate_item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  item  in  itempool : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  advancement_placed  or  ( progress_done  and  ( item . advancement  or  item . priority ) ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  item . advancement : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                candidate_item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . unlocks_new_location ( item ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  item_to_place  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # check if we can reach all locations and that is why we find no new locations to place 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  not  progress_done  and  len ( world . get_reachable_locations ( ) )  ==  len ( world . get_locations ( ) ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                progress_done  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # check if we have now placed all advancement items 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  progress_done : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                advancement_placed  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # we might be in a situation where all new locations require multiple items to reach. If that is the case, just place any advancement item we've found and continue trying 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  candidate_item_to_place  is  not  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  candidate_item_to_place 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # we placed all available progress items. Maybe the game can be beaten anyway? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . can_beat_game ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logging . getLogger ( ' ' ) . warning ( ' Not all locations reachable. Game beatable anyway. ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    progress_done  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    continue 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                raise  FillError ( ' No more progress items left to place. ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        spot_to_fill  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  location  in  fill_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # increase likelyhood of skipping a location if it has been found stale 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  not  progress_done  and  random . randint ( 0 ,  location . staleness_count )  >  2 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  location . can_fill ( world . state ,  item_to_place ) : 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                spot_to_fill  =  location 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                location . staleness_count  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # might have skipped too many locations due to potential staleness. Do not check for staleness now to find a candidate 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  spot_to_fill  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  location  in  fill_locations : 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  location . can_fill ( world . state ,  item_to_place ) : 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    spot_to_fill  =  location 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  spot_to_fill  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # we filled all reachable spots. Maybe the game can be beaten anyway? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  world . can_beat_game ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                logging . getLogger ( ' ' ) . warning ( ' Not all items placed. Game beatable anyway. ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            raise  FillError ( ' No more spots to place  %s '  %  item_to_place ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        world . push_item ( spot_to_fill ,  item_to_place ,  True ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        itempool . remove ( item_to_place ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        fill_locations . remove ( spot_to_fill ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-17 00:25:46 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logging . getLogger ( ' ' ) . debug ( ' Unplaced items:  %s  - Unfilled Locations:  %s ' ,  [ item . name  for  item  in  itempool ] ,  [ location . name  for  location  in  fill_locations ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  fill_restrictive ( world ,  base_state ,  locations ,  itempool ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  sweep_from_pool ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        new_state  =  base_state . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  item  in  itempool : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            new_state . collect ( item ,  True ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        new_state . sweep_for_events ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  new_state 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  itempool  and  locations : 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        items_to_place  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        nextpool  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        placing_players  =  set ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  item  in  reversed ( itempool ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  item . player  not  in  placing_players : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                placing_players . add ( item . player ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                items_to_place . append ( item ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                nextpool . insert ( 0 ,  item ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        itempool  =  nextpool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        maximum_exploration_state  =  sweep_from_pool ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-18 20:43:37 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        perform_access_check  =  True 
							 
						 
					
						
							
								
									
										
										
										
											2019-08-04 17:40:13 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  world . accessibility  ==  ' none ' : 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            perform_access_check  =  not  world . has_beaten_game ( maximum_exploration_state ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for  item_to_place  in  items_to_place : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            spot_to_fill  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  location  in  locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  location . can_fill ( maximum_exploration_state ,  item_to_place ,  perform_access_check ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    spot_to_fill  =  location 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    break 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  spot_to_fill  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # we filled all reachable spots. Maybe the game can be beaten anyway? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . can_beat_game ( ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-08-04 17:40:13 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    if  world . accessibility  !=  ' none ' : 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        logging . getLogger ( ' ' ) . warning ( ' Not all items placed. Game beatable anyway. (Could not place  %s ) '  %  item_to_place ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                raise  FillError ( ' No more spots to place  %s '  %  item_to_place ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            world . push_item ( spot_to_fill ,  item_to_place ,  False ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            locations . remove ( spot_to_fill ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            spot_to_fill . event  =  True 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-04 14:23:57 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								def  distribute_items_restrictive ( world ,  gftower_trash_count = 0 ,  fill_locations = None ) :  
						 
					
						
							
								
									
										
										
										
											2017-10-15 16:34:46 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    # If not passed in, then get a shuffled list of locations to fill in 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  fill_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        fill_locations  =  world . get_unfilled_locations ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        random . shuffle ( fill_locations ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get items to distribute 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( world . itempool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    progitempool  =  [ item  for  item  in  world . itempool  if  item . advancement ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    prioitempool  =  [ item  for  item  in  world . itempool  if  not  item . advancement  and  item . priority ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    restitempool  =  [ item  for  item  in  world . itempool  if  not  item . advancement  and  not  item . priority ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # fill in gtower locations with trash first 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  player  in  range ( 1 ,  world . players  +  1 ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  world . ganonstower_vanilla [ player ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            gtower_locations  =  [ location  for  location  in  fill_locations  if  ' Ganons Tower '  in  location . name  and  location . player  ==  player ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            random . shuffle ( gtower_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            trashcnt  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            while  gtower_locations  and  restitempool  and  trashcnt  <  gftower_trash_count : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                spot_to_fill  =  gtower_locations . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  restitempool . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                world . push_item ( spot_to_fill ,  item_to_place ,  False ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                fill_locations . remove ( spot_to_fill ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                trashcnt  + =  1 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( fill_locations ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-04 14:23:57 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    fill_locations . reverse ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    # Make sure the escape small key is placed first in standard keysanity to prevent running out of spots 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  world . keysanity  and  world . mode  ==  ' standard ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        progitempool . sort ( key = lambda  item :  1  if  item . name  ==  ' Small Key (Escape) '  else  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    fill_restrictive ( world ,  world . state ,  fill_locations ,  progitempool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( fill_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 16:34:46 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    fast_fill ( world ,  prioitempool ,  fill_locations ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 16:34:46 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    fast_fill ( world ,  restitempool ,  fill_locations ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-17 00:25:46 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logging . getLogger ( ' ' ) . debug ( ' Unplaced items:  %s  - Unfilled Locations:  %s ' ,  [ item . name  for  item  in  progitempool  +  prioitempool  +  restitempool ] ,  [ location . name  for  location  in  fill_locations ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 16:34:46 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								def  fast_fill ( world ,  item_pool ,  fill_locations ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  item_pool  and  fill_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        spot_to_fill  =  fill_locations . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        item_to_place  =  item_pool . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        world . push_item ( spot_to_fill ,  item_to_place ,  False ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-04 14:23:57 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								def  flood_items ( world ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # get items to distribute 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( world . itempool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    itempool  =  world . itempool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    progress_done  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # sweep once to pick up preplaced items 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    world . state . sweep_for_events ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # fill world from top of itempool while we can 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  not  progress_done : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        location_list  =  world . get_unfilled_locations ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        random . shuffle ( location_list ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        spot_to_fill  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  location  in  location_list : 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-02 00:39:53 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  location . can_fill ( world . state ,  itempool [ 0 ] ) : 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                spot_to_fill  =  location 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  spot_to_fill : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            item  =  itempool . pop ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            world . push_item ( spot_to_fill ,  item ,  True ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # ran out of spots, check if we need to step in and correct things 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  len ( world . get_reachable_locations ( ) )  ==  len ( world . get_locations ( ) ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            progress_done  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # need to place a progress item instead of an already placed item, find candidate 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        candidate_item_to_place  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  item  in  itempool : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  item . advancement : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                candidate_item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  world . unlocks_new_location ( item ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    item_to_place  =  item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # we might be in a situation where all new locations require multiple items to reach. If that is the case, just place any advancement item we've found and continue trying 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  item_to_place  is  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  candidate_item_to_place  is  not  None : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                item_to_place  =  candidate_item_to_place 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-27 16:21:32 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                raise  FillError ( ' No more progress items left to place. ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-15 15:35:45 -04:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # find item to replace with progress item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        location_list  =  world . get_reachable_locations ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        random . shuffle ( location_list ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  location  in  location_list : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  location . item  is  not  None  and  not  location . item . advancement  and  not  location . item . priority  and  not  location . item . key : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # safe to replace 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                replace_item  =  location . item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                replace_item . location  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                itempool . append ( replace_item ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                world . push_item ( location ,  item_to_place ,  True ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                itempool . remove ( item_to_place ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  balance_multiworld_progression ( world ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    state  =  CollectionState ( world ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    checked_locations  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    unchecked_locations  =  world . get_locations ( ) . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    random . shuffle ( unchecked_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    reachable_locations_count  =  { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  player  in  range ( 1 ,  world . players  +  1 ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        reachable_locations_count [ player ]  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  get_sphere_locations ( sphere_state ,  locations ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  not  world . keysanity : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            sphere_state . sweep_for_events ( key_only = True ,  locations = locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  [ loc  for  loc  in  locations  if  sphere_state . can_reach ( loc ) ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  True : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        sphere_locations  =  get_sphere_locations ( state ,  unchecked_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  location  in  sphere_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            unchecked_locations . remove ( location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            reachable_locations_count [ location . player ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  checked_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            average_reachable_locations  =  sum ( reachable_locations_count . values ( ) )  /  world . players 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            threshold  =  ( ( average_reachable_locations  +  max ( reachable_locations_count . values ( ) ) )  /  2 )  *  0.8  #todo: probably needs some tweaking 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            balancing_players  =  [ player  for  player ,  reachables  in  reachable_locations_count . items ( )  if  reachables  <  threshold ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  balancing_players : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                balancing_state  =  state . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                balancing_unchecked_locations  =  unchecked_locations . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                balancing_reachables  =  reachable_locations_count . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                balancing_sphere  =  sphere_locations . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                candidate_items  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                while  True : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    for  location  in  balancing_sphere : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  location . event : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            balancing_state . collect ( location . item ,  True ,  location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  location . item . player  in  balancing_players : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                candidate_items . append ( location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    balancing_sphere  =  get_sphere_locations ( balancing_state ,  balancing_unchecked_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    for  location  in  balancing_sphere : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        balancing_unchecked_locations . remove ( location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        balancing_reachables [ location . player ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  world . has_beaten_game ( balancing_state )  or  all ( [ reachables  > =  threshold  for  reachables  in  balancing_reachables . values ( ) ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                unlocked_locations  =  [ l  for  l  in  unchecked_locations  if  l  not  in  balancing_unchecked_locations ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                items_to_replace  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                for  player  in  balancing_players : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    locations_to_test  =  [ l  for  l  in  unlocked_locations  if  l . player  ==  player ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    items_to_test  =  [ l  for  l  in  candidate_items  if  l . item . player  ==  player  and  l . player  !=  player ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    while  items_to_test : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        testing  =  items_to_test . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        reducing_state  =  state . copy ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        for  location  in  [ * [ l  for  l  in  items_to_replace  if  l . item . player  ==  player ] ,  * items_to_test ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            reducing_state . collect ( location . item ,  True ,  location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        reducing_state . sweep_for_events ( locations = locations_to_test ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-08-04 12:32:35 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        if  testing . locked : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        if  world . has_beaten_game ( balancing_state ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  not  world . has_beaten_game ( reducing_state ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                items_to_replace . append ( testing ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            reduced_sphere  =  get_sphere_locations ( reducing_state ,  locations_to_test ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  reachable_locations_count [ player ]  +  len ( reduced_sphere )  <  threshold : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                items_to_replace . append ( testing ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                replaced_items  =  False 
							 
						 
					
						
							
								
									
										
										
										
											2019-08-04 12:32:35 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                locations_for_replacing  =  [ l  for  l  in  checked_locations  if  not  l . event  and  not  l . locked ] 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                while  locations_for_replacing  and  items_to_replace : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    new_location  =  locations_for_replacing . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    old_location  =  items_to_replace . pop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    new_location . item ,  old_location . item  =  old_location . item ,  new_location . item 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    new_location . event  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    old_location . event  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    state . collect ( new_location . item ,  True ,  new_location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    replaced_items  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  replaced_items : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    for  location  in  get_sphere_locations ( state ,  [ l  for  l  in  unlocked_locations  if  l . player  in  balancing_players ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        unchecked_locations . remove ( location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        reachable_locations_count [ location . player ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        sphere_locations . append ( location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  location  in  sphere_locations : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  location . event : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                state . collect ( location . item ,  True ,  location ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        checked_locations . extend ( sphere_locations ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  world . has_beaten_game ( state ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            break