| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  | from . import Constants | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  | from typing import TYPE_CHECKING | 
					
						
							|  |  |  | if TYPE_CHECKING: | 
					
						
							|  |  |  |     from . import MinecraftWorld | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  | def shuffle_structures(self: "MinecraftWorld") -> None: | 
					
						
							|  |  |  |     multiworld = self.multiworld | 
					
						
							|  |  |  |     player = self.player | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     default_connections = Constants.region_info["default_connections"] | 
					
						
							|  |  |  |     illegal_connections = Constants.region_info["illegal_connections"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get all unpaired exits and all regions without entrances (except the Menu) | 
					
						
							|  |  |  |     # This function is destructive on these lists.  | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |     exits = [exit.name for r in multiworld.regions if r.player == player for exit in r.exits if exit.connected_region is None] | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |     structs = [r.name for r in multiworld.regions if r.player == player and r.entrances == [] and r.name != 'Menu'] | 
					
						
							|  |  |  |     exits_spoiler = exits[:] # copy the original order for the spoiler log | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pairs = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_pair(exit, struct):  | 
					
						
							|  |  |  |         if (exit in exits) and (struct in structs) and (exit not in illegal_connections.get(struct, [])): | 
					
						
							|  |  |  |             pairs[exit] = struct | 
					
						
							|  |  |  |             exits.remove(exit) | 
					
						
							|  |  |  |             structs.remove(struct) | 
					
						
							|  |  |  |         else:  | 
					
						
							|  |  |  |             raise Exception(f"Invalid connection: {exit} => {struct} for player {player} ({multiworld.player_name[player]})") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Connect plando structures first | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |     if self.options.plando_connections: | 
					
						
							|  |  |  |         for conn in self.plando_connections: | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |             set_pair(conn.entrance, conn.exit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # The algorithm tries to place the most restrictive structures first. This algorithm always works on the | 
					
						
							|  |  |  |     # relatively small set of restrictions here, but does not work on all possible inputs with valid configurations.  | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |     if self.options.shuffle_structures: | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |         structs.sort(reverse=True, key=lambda s: len(illegal_connections.get(s, []))) | 
					
						
							|  |  |  |         for struct in structs[:]:  | 
					
						
							|  |  |  |             try:  | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |                 exit = self.random.choice([e for e in exits if e not in illegal_connections.get(struct, [])]) | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |             except IndexError:  | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |                 raise Exception(f"No valid structure placements remaining for player {player} ({self.player_name})") | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |             set_pair(exit, struct) | 
					
						
							|  |  |  |     else: # write remaining default connections | 
					
						
							|  |  |  |         for (exit, struct) in default_connections:  | 
					
						
							|  |  |  |             if exit in exits:  | 
					
						
							|  |  |  |                 set_pair(exit, struct) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Make sure we actually paired everything; might fail if plando | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         assert len(exits) == len(structs) == 0 | 
					
						
							|  |  |  |     except AssertionError:  | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |         raise Exception(f"Failed to connect all Minecraft structures for player {player} ({self.player_name})") | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for exit in exits_spoiler: | 
					
						
							|  |  |  |         multiworld.get_entrance(exit, player).connect(multiworld.get_region(pairs[exit], player)) | 
					
						
							| 
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 |  |  |         if self.options.shuffle_structures or self.options.plando_connections: | 
					
						
							| 
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 |  |  |             multiworld.spoiler.set_entrance(exit, pairs[exit], 'entrance', player) |