| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  | from typing import List, Iterable | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | import unittest | 
					
						
							|  |  |  | from worlds.AutoWorld import World | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | from Fill import FillError, balance_multiworld_progression, fill_restrictive, distribute_items_restrictive | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  | from BaseClasses import Entrance, LocationProgressType, MultiWorld, Region, RegionType, Item, Location, \ | 
					
						
							|  |  |  |     ItemClassification | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  | from worlds.generic.Rules import CollectionRule, locality_rules, set_rule | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | def generate_multi_world(players: int = 1) -> MultiWorld: | 
					
						
							|  |  |  |     multi_world = MultiWorld(players) | 
					
						
							|  |  |  |     multi_world.player_name = {} | 
					
						
							|  |  |  |     for i in range(players): | 
					
						
							|  |  |  |         player_id = i+1 | 
					
						
							|  |  |  |         world = World(multi_world, player_id) | 
					
						
							|  |  |  |         multi_world.game[player_id] = world | 
					
						
							|  |  |  |         multi_world.worlds[player_id] = world | 
					
						
							|  |  |  |         multi_world.player_name[player_id] = "Test Player " + str(player_id) | 
					
						
							|  |  |  |         region = Region("Menu", RegionType.Generic, | 
					
						
							|  |  |  |                         "Menu Region Hint", player_id, multi_world) | 
					
						
							|  |  |  |         multi_world.regions.append(region) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     multi_world.set_seed(0) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     multi_world.set_default_common_options() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return multi_world | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | class PlayerDefinition(object): | 
					
						
							|  |  |  |     world: MultiWorld | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |     id: int | 
					
						
							|  |  |  |     menu: Region | 
					
						
							| 
									
										
										
										
											2022-01-06 06:09:15 +01:00
										 |  |  |     locations: List[Location] | 
					
						
							|  |  |  |     prog_items: List[Item] | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     basic_items: List[Item] | 
					
						
							|  |  |  |     regions: List[Region] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, world: MultiWorld, id: int, menu: Region, locations: List[Location] = [], prog_items: List[Item] = [], basic_items: List[Item] = []): | 
					
						
							|  |  |  |         self.world = world | 
					
						
							|  |  |  |         self.id = id | 
					
						
							|  |  |  |         self.menu = menu | 
					
						
							|  |  |  |         self.locations = locations | 
					
						
							|  |  |  |         self.prog_items = prog_items | 
					
						
							|  |  |  |         self.basic_items = basic_items | 
					
						
							|  |  |  |         self.regions = [menu] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def generate_region(self, parent: Region, size: int, access_rule: CollectionRule = lambda state: True) -> Region: | 
					
						
							|  |  |  |         region_tag = "_region" + str(len(self.regions)) | 
					
						
							|  |  |  |         region_name = "player" + str(self.id) + region_tag | 
					
						
							|  |  |  |         region = Region("player" + str(self.id) + region_tag, RegionType.Generic, | 
					
						
							|  |  |  |                         "Region Hint", self.id, self.world) | 
					
						
							| 
									
										
										
										
											2022-08-05 17:09:21 +02:00
										 |  |  |         self.locations += generate_locations(size, self.id, None, region, region_tag) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         entrance = Entrance(self.id, region_name + "_entrance", parent) | 
					
						
							|  |  |  |         parent.exits.append(entrance) | 
					
						
							|  |  |  |         entrance.connect(region) | 
					
						
							|  |  |  |         entrance.access_rule = access_rule | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.regions.append(region) | 
					
						
							|  |  |  |         self.world.regions.append(region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return region | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def fillRegion(world: MultiWorld, region: Region, items: List[Item]) -> List[Item]: | 
					
						
							|  |  |  |     items = items.copy() | 
					
						
							|  |  |  |     while len(items) > 0: | 
					
						
							|  |  |  |         location = region.locations.pop(0) | 
					
						
							|  |  |  |         region.locations.append(location) | 
					
						
							|  |  |  |         if location.item: | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  |         item = items.pop(0) | 
					
						
							|  |  |  |         world.push_item(location, item, False) | 
					
						
							|  |  |  |         location.event = item.advancement | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def regionContains(region: Region, item: Item) -> bool: | 
					
						
							|  |  |  |     for location in region.locations: | 
					
						
							|  |  |  |         if location.item == item: | 
					
						
							|  |  |  |             return True | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     return False | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | def generate_player_data(multi_world: MultiWorld, player_id: int, location_count: int = 0, prog_item_count: int = 0, basic_item_count: int = 0) -> PlayerDefinition: | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |     menu = multi_world.get_region("Menu", player_id) | 
					
						
							|  |  |  |     locations = generate_locations(location_count, player_id, None, menu) | 
					
						
							|  |  |  |     prog_items = generate_items(prog_item_count, player_id, True) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     multi_world.itempool += prog_items | 
					
						
							|  |  |  |     basic_items = generate_items(basic_item_count, player_id, False) | 
					
						
							|  |  |  |     multi_world.itempool += basic_items | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     return PlayerDefinition(multi_world, player_id, menu, locations, prog_items, basic_items) | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | def generate_locations(count: int, player_id: int, address: int = None, region: Region = None, tag: str = "") -> List[Location]: | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     locations = [] | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     prefix = "player" + str(player_id) + tag + "_location" | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     for i in range(count): | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         name = prefix + str(i) | 
					
						
							| 
									
										
										
										
											2021-12-20 07:59:36 -07:00
										 |  |  |         location = Location(player_id, name, address, region) | 
					
						
							|  |  |  |         locations.append(location) | 
					
						
							|  |  |  |         region.locations.append(location) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     return locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-06 06:09:15 +01:00
										 |  |  | def generate_items(count: int, player_id: int, advancement: bool = False, code: int = None) -> List[Item]: | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     items = [] | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |     item_type = "prog" if advancement else "" | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     for i in range(count): | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |         name = "player" + str(player_id) + "_" + item_type + "item" + str(i) | 
					
						
							|  |  |  |         items.append(Item(name, | 
					
						
							|  |  |  |                           ItemClassification.progression if advancement else ItemClassification.filler, | 
					
						
							|  |  |  |                           code, player_id)) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |     return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  | def names(objs: list) -> Iterable[str]: | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |     return map(lambda o: o.name, objs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | class TestFillRestrictive(unittest.TestCase): | 
					
						
							|  |  |  |     def test_basic_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         item0 = player1.prog_items[0] | 
					
						
							|  |  |  |         item1 = player1.prog_items[1] | 
					
						
							|  |  |  |         loc0 = player1.locations[0] | 
					
						
							|  |  |  |         loc1 = player1.locations[1] | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          player1.locations, player1.prog_items) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(loc0.item, item1) | 
					
						
							|  |  |  |         self.assertEqual(loc1.item, item0) | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         self.assertEqual([], player1.locations) | 
					
						
							|  |  |  |         self.assertEqual([], player1.prog_items) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_ordered_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         items = player1.prog_items | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id) and state.has(items[1].name, player1.id) | 
					
						
							|  |  |  |         set_rule(locations[1], lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id)) | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         self.assertEqual(locations[0].item, items[0]) | 
					
						
							|  |  |  |         self.assertEqual(locations[1].item, items[1]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_partial_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-30 10:50:18 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, 3, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         item0 = player1.prog_items[0] | 
					
						
							|  |  |  |         item1 = player1.prog_items[1] | 
					
						
							|  |  |  |         loc0 = player1.locations[0] | 
					
						
							|  |  |  |         loc1 = player1.locations[1] | 
					
						
							|  |  |  |         loc2 = player1.locations[2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id) and state.has(item1.name, player1.id) | 
					
						
							|  |  |  |         set_rule(loc1, lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id)) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         # forces a swap | 
					
						
							| 
									
										
										
										
											2021-12-30 10:50:18 -07:00
										 |  |  |         set_rule(loc2, lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id)) | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          player1.locations, player1.prog_items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(loc0.item, item0) | 
					
						
							|  |  |  |         self.assertEqual(loc1.item, item1) | 
					
						
							|  |  |  |         self.assertEqual(1, len(player1.locations)) | 
					
						
							|  |  |  |         self.assertEqual(player1.locations[0], loc2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_minimal_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         items = player1.prog_items | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |         multi_world.accessibility[player1.id].value = multi_world.accessibility[player1.id].option_minimal | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |             items[1].name, player1.id) | 
					
						
							|  |  |  |         set_rule(locations[1], lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |                          player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         self.assertEqual(locations[0].item, items[1]) | 
					
						
							|  |  |  |         # Unnecessary unreachable Item | 
					
						
							|  |  |  |         self.assertEqual(locations[1].item, items[0]) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_reversed_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         item0 = player1.prog_items[0] | 
					
						
							|  |  |  |         item1 = player1.prog_items[1] | 
					
						
							|  |  |  |         loc0 = player1.locations[0] | 
					
						
							|  |  |  |         loc1 = player1.locations[1] | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id) and state.has(item1.name, player1.id) | 
					
						
							|  |  |  |         set_rule(loc1, lambda state: state.has(item1.name, player1.id)) | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          player1.locations, player1.prog_items) | 
					
						
							| 
									
										
										
										
											2021-12-18 17:54:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(loc0.item, item1) | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  |         self.assertEqual(loc1.item, item0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_multi_step_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 4, 4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         items = player1.prog_items | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             items[2].name, player1.id) and state.has(items[3].name, player1.id) | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         set_rule(locations[1], lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id)) | 
					
						
							|  |  |  |         set_rule(locations[2], lambda state: state.has( | 
					
						
							|  |  |  |             items[1].name, player1.id)) | 
					
						
							|  |  |  |         set_rule(locations[3], lambda state: state.has( | 
					
						
							|  |  |  |             items[1].name, player1.id)) | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         self.assertEqual(locations[0].item, items[1]) | 
					
						
							|  |  |  |         self.assertEqual(locations[1].item, items[2]) | 
					
						
							|  |  |  |         self.assertEqual(locations[2].item, items[0]) | 
					
						
							|  |  |  |         self.assertEqual(locations[3].item, items[3]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_impossible_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-28 11:57:48 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							|  |  |  |         items = player1.prog_items | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id) and state.has(items[1].name, player1.id) | 
					
						
							|  |  |  |         set_rule(locations[1], lambda state: state.has( | 
					
						
							|  |  |  |             items[1].name, player1.id)) | 
					
						
							|  |  |  |         set_rule(locations[0], lambda state: state.has( | 
					
						
							|  |  |  |             items[0].name, player1.id)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-30 08:22:46 -07:00
										 |  |  |         self.assertRaises(FillError, fill_restrictive, multi_world, multi_world.state, | 
					
						
							|  |  |  |                           player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_circular_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-20 17:47:04 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 3, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         item0 = player1.prog_items[0] | 
					
						
							|  |  |  |         item1 = player1.prog_items[1] | 
					
						
							|  |  |  |         item2 = player1.prog_items[2] | 
					
						
							|  |  |  |         loc0 = player1.locations[0] | 
					
						
							|  |  |  |         loc1 = player1.locations[1] | 
					
						
							|  |  |  |         loc2 = player1.locations[2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id) and state.has(item1.name, player1.id) and state.has(item2.name, player1.id) | 
					
						
							|  |  |  |         set_rule(loc1, lambda state: state.has(item0.name, player1.id)) | 
					
						
							|  |  |  |         set_rule(loc2, lambda state: state.has(item1.name, player1.id)) | 
					
						
							|  |  |  |         set_rule(loc0, lambda state: state.has(item2.name, player1.id)) | 
					
						
							| 
									
										
										
										
											2021-12-30 08:22:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(FillError, fill_restrictive, multi_world, multi_world.state, | 
					
						
							|  |  |  |                           player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-20 18:14:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_competing_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-20 18:14:50 -07:00
										 |  |  |         multi_world = generate_multi_world() | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							| 
									
										
										
										
											2021-12-20 18:14:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         item0 = player1.prog_items[0] | 
					
						
							|  |  |  |         item1 = player1.prog_items[1] | 
					
						
							|  |  |  |         loc1 = player1.locations[1] | 
					
						
							| 
									
										
										
										
											2021-12-20 18:14:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             item0.name, player1.id) and state.has(item0.name, player1.id) and state.has(item1.name, player1.id) | 
					
						
							|  |  |  |         set_rule(loc1, lambda state: state.has(item0.name, player1.id) | 
					
						
							|  |  |  |                  and state.has(item1.name, player1.id)) | 
					
						
							| 
									
										
										
										
											2021-12-30 10:50:18 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-30 08:22:46 -07:00
										 |  |  |         self.assertRaises(FillError, fill_restrictive, multi_world, multi_world.state, | 
					
						
							|  |  |  |                           player1.locations.copy(), player1.prog_items.copy()) | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_multiplayer_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world = generate_multi_world(2) | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							|  |  |  |         player2 = generate_player_data(multi_world, 2, 2, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player1.prog_items[0].name, player1.id) and state.has( | 
					
						
							|  |  |  |             player1.prog_items[1].name, player1.id) | 
					
						
							|  |  |  |         multi_world.completion_condition[player2.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player2.prog_items[0].name, player2.id) and state.has( | 
					
						
							|  |  |  |             player2.prog_items[1].name, player2.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, player1.locations + | 
					
						
							|  |  |  |                          player2.locations, player1.prog_items + player2.prog_items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(player1.locations[0].item, player1.prog_items[1]) | 
					
						
							|  |  |  |         self.assertEqual(player1.locations[1].item, player2.prog_items[1]) | 
					
						
							|  |  |  |         self.assertEqual(player2.locations[0].item, player1.prog_items[0]) | 
					
						
							|  |  |  |         self.assertEqual(player2.locations[1].item, player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |     def test_multiplayer_rules_fill(self): | 
					
						
							| 
									
										
										
										
											2021-12-21 22:55:10 -07:00
										 |  |  |         multi_world = generate_multi_world(2) | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, 2, 2) | 
					
						
							|  |  |  |         player2 = generate_player_data(multi_world, 2, 2, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player1.prog_items[0].name, player1.id) and state.has( | 
					
						
							|  |  |  |             player1.prog_items[1].name, player1.id) | 
					
						
							|  |  |  |         multi_world.completion_condition[player2.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player2.prog_items[0].name, player2.id) and state.has( | 
					
						
							|  |  |  |             player2.prog_items[1].name, player2.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         set_rule(player2.locations[1], lambda state: state.has( | 
					
						
							|  |  |  |             player2.prog_items[0].name, player2.id)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, player1.locations + | 
					
						
							|  |  |  |                          player2.locations, player1.prog_items + player2.prog_items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(player1.locations[0].item, player2.prog_items[0]) | 
					
						
							|  |  |  |         self.assertEqual(player1.locations[1].item, player2.prog_items[1]) | 
					
						
							|  |  |  |         self.assertEqual(player2.locations[0].item, player1.prog_items[0]) | 
					
						
							|  |  |  |         self.assertEqual(player2.locations[1].item, player1.prog_items[1]) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |     def test_restrictive_progress(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data(multi_world, 1, prog_item_count=25) | 
					
						
							|  |  |  |         items = player1.prog_items.copy() | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has_all( | 
					
						
							|  |  |  |             names(player1.prog_items), player1.id) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-29 09:20:04 -07:00
										 |  |  |         player1.generate_region(player1.menu, 5) | 
					
						
							|  |  |  |         player1.generate_region(player1.menu, 5, lambda state: state.has_all( | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |             names(items[2:7]), player1.id)) | 
					
						
							| 
									
										
										
										
											2022-01-29 09:20:04 -07:00
										 |  |  |         player1.generate_region(player1.menu, 5, lambda state: state.has_all( | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |             names(items[7:12]), player1.id)) | 
					
						
							| 
									
										
										
										
											2022-01-29 09:20:04 -07:00
										 |  |  |         player1.generate_region(player1.menu, 5, lambda state: state.has_all( | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |             names(items[12:17]), player1.id)) | 
					
						
							| 
									
										
										
										
											2022-01-29 09:20:04 -07:00
										 |  |  |         player1.generate_region(player1.menu, 5, lambda state: state.has_all( | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |             names(items[17:22]), player1.id)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations = multi_world.get_unfilled_locations() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fill_restrictive(multi_world, multi_world.state, | 
					
						
							|  |  |  |                          locations, player1.prog_items) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestDistributeItemsRestrictive(unittest.TestCase): | 
					
						
							|  |  |  |     def test_basic_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  |         prog_items = player1.prog_items | 
					
						
							|  |  |  |         basic_items = player1.basic_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 20:06:25 -04:00
										 |  |  |         self.assertEqual(locations[0].item, basic_items[1]) | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  |         self.assertFalse(locations[0].event) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         self.assertEqual(locations[1].item, prog_items[0]) | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  |         self.assertTrue(locations[1].event) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         self.assertEqual(locations[2].item, prog_items[1]) | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  |         self.assertTrue(locations[2].event) | 
					
						
							| 
									
										
										
										
											2022-09-16 20:06:25 -04:00
										 |  |  |         self.assertEqual(locations[3].item, basic_items[0]) | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  |         self.assertFalse(locations[3].event) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_excluded_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[1].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  |         locations[2].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertFalse(locations[1].item.advancement) | 
					
						
							|  |  |  |         self.assertFalse(locations[2].item.advancement) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_non_excluded_item_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  |         basic_items = player1.basic_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[1].progress_type = LocationProgressType.EXCLUDED | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |         basic_items[1].classification = ItemClassification.useful | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(locations[1].item, basic_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_too_many_excluded_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[0].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  |         locations[1].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  |         locations[2].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(FillError, distribute_items_restrictive, multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_non_excluded_item_must_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  |         basic_items = player1.basic_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[1].progress_type = LocationProgressType.EXCLUDED | 
					
						
							|  |  |  |         locations[2].progress_type = LocationProgressType.EXCLUDED | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |         basic_items[0].classification = ItemClassification.useful | 
					
						
							|  |  |  |         basic_items[1].classification = ItemClassification.useful | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(FillError, distribute_items_restrictive, multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_priority_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[0].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         locations[3].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(locations[0].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(locations[3].item.advancement) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_excess_priority_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         locations = player1.locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         locations[0].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         locations[1].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         locations[2].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertFalse(locations[3].item.advancement) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_multiple_world_priority_distribute(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world(3) | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         player2 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 2, 4, prog_item_count=1, basic_item_count=3) | 
					
						
							|  |  |  |         player3 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 3, 6, prog_item_count=4, basic_item_count=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         player1.locations[2].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         player1.locations[3].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         player2.locations[1].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         player3.locations[0].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         player3.locations[1].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         player3.locations[2].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         player3.locations[3].progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(player1.locations[2].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player1.locations[3].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player2.locations[1].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player3.locations[0].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player3.locations[1].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player3.locations[2].item.advancement) | 
					
						
							|  |  |  |         self.assertTrue(player3.locations[3].item.advancement) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-21 20:34:59 -07:00
										 |  |  |     def test_can_remove_locations_in_fill_hook(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         removed_item: list[Item] = [] | 
					
						
							|  |  |  |         removed_location: list[Location] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 20:06:25 -04:00
										 |  |  |         def fill_hook(progitempool, usefulitempool, filleritempool, fill_locations): | 
					
						
							|  |  |  |             removed_item.append(filleritempool.pop(0)) | 
					
						
							| 
									
										
										
										
											2022-01-21 20:34:59 -07:00
										 |  |  |             removed_location.append(fill_locations.pop(0)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.worlds[player1.id].fill_hook = fill_hook | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertIsNone(removed_item[0].location) | 
					
						
							|  |  |  |         self.assertIsNone(removed_location[0].item) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 09:25:42 -07:00
										 |  |  |     def test_seed_robust_to_item_order(self): | 
					
						
							|  |  |  |         mw1 = generate_multi_world() | 
					
						
							|  |  |  |         gen1 = generate_player_data( | 
					
						
							|  |  |  |             mw1, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         distribute_items_restrictive(mw1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mw2 = generate_multi_world() | 
					
						
							|  |  |  |         gen2 = generate_player_data( | 
					
						
							|  |  |  |             mw2, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         mw2.itempool.append(mw2.itempool.pop(0)) | 
					
						
							|  |  |  |         distribute_items_restrictive(mw2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[0].item, gen2.locations[0].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[1].item, gen2.locations[1].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[2].item, gen2.locations[2].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[3].item, gen2.locations[3].item) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_seed_robust_to_location_order(self): | 
					
						
							|  |  |  |         mw1 = generate_multi_world() | 
					
						
							|  |  |  |         gen1 = generate_player_data( | 
					
						
							|  |  |  |             mw1, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         distribute_items_restrictive(mw1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mw2 = generate_multi_world() | 
					
						
							|  |  |  |         gen2 = generate_player_data( | 
					
						
							|  |  |  |             mw2, 1, 4, prog_item_count=2, basic_item_count=2) | 
					
						
							|  |  |  |         reg = mw2.get_region("Menu", gen2.id) | 
					
						
							|  |  |  |         reg.locations.append(reg.locations.pop(0)) | 
					
						
							|  |  |  |         distribute_items_restrictive(mw2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[0].item, gen2.locations[0].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[1].item, gen2.locations[1].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[2].item, gen2.locations[2].item) | 
					
						
							|  |  |  |         self.assertEqual(gen1.locations[3].item, gen2.locations[3].item) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-29 09:20:04 -07:00
										 |  |  |     def test_can_reserve_advancement_items_for_general_fill(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world() | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, location_count=5, prog_item_count=5) | 
					
						
							|  |  |  |         items = player1.prog_items | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has_all( | 
					
						
							|  |  |  |             names(items), player1.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         location = player1.locations[0] | 
					
						
							|  |  |  |         location.progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  |         location.item_rule = lambda item: item != items[ | 
					
						
							|  |  |  |             0] and item != items[1] and item != items[2] and item != items[3] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(location.item, items[4]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  |     def test_non_excluded_local_items(self): | 
					
						
							|  |  |  |         multi_world = generate_multi_world(2) | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, location_count=5, basic_item_count=5) | 
					
						
							|  |  |  |         player2 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 2, location_count=5, basic_item_count=5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item in multi_world.get_items(): | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |             item.classification = ItemClassification.useful | 
					
						
							| 
									
										
										
										
											2022-01-31 14:23:01 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         multi_world.local_items[player1.id].value = set(names(player1.basic_items)) | 
					
						
							|  |  |  |         multi_world.local_items[player2.id].value = set(names(player2.basic_items)) | 
					
						
							|  |  |  |         locality_rules(multi_world, player1.id) | 
					
						
							|  |  |  |         locality_rules(multi_world, player2.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         distribute_items_restrictive(multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item in multi_world.get_items(): | 
					
						
							|  |  |  |             self.assertEqual(item.player, item.location.player) | 
					
						
							|  |  |  |             self.assertFalse(item.location.event, False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestBalanceMultiworldProgression(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2022-05-11 00:13:21 -07:00
										 |  |  |     def assertRegionContains(self, region: Region, item: Item) -> bool: | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         for location in region.locations: | 
					
						
							|  |  |  |             if location.item and location.item == item: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.fail("Expected " + region.name + " to contain " + item.name + | 
					
						
							|  |  |  |                   "\n Contains" + str(list(map(lambda location: location.item, region.locations)))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-11 00:13:21 -07:00
										 |  |  |     def setUp(self) -> None: | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         multi_world = generate_multi_world(2) | 
					
						
							|  |  |  |         self.multi_world = multi_world | 
					
						
							|  |  |  |         player1 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 1, prog_item_count=2, basic_item_count=40) | 
					
						
							|  |  |  |         self.player1 = player1 | 
					
						
							|  |  |  |         player2 = generate_player_data( | 
					
						
							|  |  |  |             multi_world, 2, prog_item_count=2, basic_item_count=40) | 
					
						
							|  |  |  |         self.player2 = player2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multi_world.completion_condition[player1.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player1.prog_items[0].name, player1.id) and state.has( | 
					
						
							|  |  |  |             player1.prog_items[1].name, player1.id) | 
					
						
							|  |  |  |         multi_world.completion_condition[player2.id] = lambda state: state.has( | 
					
						
							|  |  |  |             player2.prog_items[0].name, player2.id) and state.has( | 
					
						
							|  |  |  |             player2.prog_items[1].name, player2.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         items = player1.basic_items + player2.basic_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Sphere 1 | 
					
						
							|  |  |  |         region = player1.generate_region(player1.menu, 20) | 
					
						
							|  |  |  |         items = fillRegion(multi_world, region, [ | 
					
						
							| 
									
										
										
										
											2022-01-27 21:40:08 -07:00
										 |  |  |             player1.prog_items[0]] + items) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Sphere 2 | 
					
						
							|  |  |  |         region = player1.generate_region( | 
					
						
							|  |  |  |             player1.regions[1], 20, lambda state: state.has(player1.prog_items[0].name, player1.id)) | 
					
						
							|  |  |  |         items = fillRegion( | 
					
						
							|  |  |  |             multi_world, region, [player1.prog_items[1], player2.prog_items[0]] + items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Sphere 3 | 
					
						
							|  |  |  |         region = player2.generate_region( | 
					
						
							|  |  |  |             player2.menu, 20, lambda state: state.has(player2.prog_items[0].name, player2.id)) | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |         fillRegion(multi_world, region, [player2.prog_items[1]] + items) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-11 00:13:21 -07:00
										 |  |  |     def test_balances_progression(self) -> None: | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player1.id].value = 50 | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player2.id].value = 50 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         balance_multiworld_progression(self.multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[1], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-11 00:13:21 -07:00
										 |  |  |     def test_balances_progression_light(self) -> None: | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player1.id].value = 1 | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player2.id].value = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         balance_multiworld_progression(self.multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # TODO: arrange for a result that's different from the default | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[1], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_balances_progression_heavy(self) -> None: | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player1.id].value = 99 | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player2.id].value = 99 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         balance_multiworld_progression(self.multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # TODO: arrange for a result that's different from the default | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[1], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_skips_balancing_progression(self) -> None: | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player1.id].value = 0 | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player2.id].value = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         balance_multiworld_progression(self.multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_ignores_priority_locations(self) -> None: | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player1.id].value = 50 | 
					
						
							|  |  |  |         self.multi_world.progression_balancing[self.player2.id].value = 50 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |         self.player2.prog_items[0].location.progress_type = LocationProgressType.PRIORITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         balance_multiworld_progression(self.multi_world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRegionContains( | 
					
						
							|  |  |  |             self.player1.regions[2], self.player2.prog_items[0]) |