def test_state_copy_time(self): results = dict() l = 6 copies = dict() for t in range(10, 100, 20): tower : Tower_State = Tower_State() for new_block in [Block(block_mesh, 'flat_wide', (0, 0, i)) for i in range(1, t)]: if tower.can_add(new_block): tower.add(new_block) s = time.time() copies[t] = [copy(tower) for _ in range(l)] e = time.time() - s results[t] = e / l print(results[t]) pp(results) for height, tower_copy_list in copies.items(): for i, tower in enumerate(tower_copy_list): new_block = Block(block_mesh, 'flat_wide', (0, i, height)) if tower.can_add(new_block): tower.add(new_block) towers = [] for copy_list in copies.values(): towers += copy_list for i, tower1 in enumerate(towers): for j, tower2 in enumerate(towers[i+1:]): self.assertNotEqual(tower1, tower2) self.assertNotEqual(tower1._connectivity, tower2._connectivity)
def test_tower_copy(self): tower1 = Tower_State() tower1_copy = copy(tower1) self.assertEqual(tower1, tower1_copy) self.assertTrue(tower1 is not tower1_copy) tower2 : Tower_State = Tower_State() for new_block in [Block(block_mesh, 'flat_wide', (0, 0, i)) for i in range(1, 50)]: if tower2.can_add(new_block): tower2.add(new_block) tower2_copy : Tower_State = copy(tower2) self.assertEqual(tower2, tower2_copy) self.assertTrue(tower2 is not tower2_copy) new_block = Block(block_mesh, 'flat_wide', (0, 0, 50)) if tower2.can_add(new_block): tower2.add(new_block) print("Added new block to tower 2, {}".format(new_block.__str__())) self.assertNotEqual(tower2, tower2_copy) self.assertTrue(tower2 is not tower2_copy) self.assertNotEqual(tower2._connectivity, tower2_copy._connectivity) self.assertNotEqual(list(tower2._orientation_counter), list(tower2_copy._orientation_counter))
def test_constructor(self): floor = RingFloor(floor_mesh) if DISPLAY: display([floor.render()]) block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) if DISPLAY: display_colored([floor.render(), block1.render()], [to_rgba((0.1, 0.1, 0.1), 0.001 ), 'b'])
def get_successors(self, tower_state: Tower_State): print("Building succesors for state of height:{}".format(tower_state._max_level)) pp(tower_state) all_possible_son_desc = [] for father_block in tower_state.gen_blocks(no_floor=False, filter_saturated_block=False): if father_block.is_saturated(tower_state): self._num_of_blocks_saturated += 1 continue all_possible_son_desc.extend(filter( lambda desc: not tower_state.is_bad_block(Block.gen_str(desc)), father_block.gen_possible_block_descriptors( limit_orientation=lambda o: father_block.is_perpendicular(o), limit_len=self._limit_sons, random_order=self._gen_randomly ) ) ) if self._gen_randomly: shuffle(all_possible_son_desc) else: all_possible_son_desc.sort(key=lambda desc: desc[1][Z], reverse=True) for _ in range(self._limit_branching): new_tower = copy(tower_state) actions = [] while len(actions) < self._num_of_blocks_in_action: if all_possible_son_desc: desc = all_possible_son_desc.pop() else: break if tower_state.is_bad_block(Block.gen_str(desc)): self._num_of_descriptors_disqualified += 1 continue son_block = Block(BLOCK_MESH, *desc) if new_tower.can_add(son_block): new_tower.add(son_block) actions.append(son_block) else: self._num_of_blocks_disqualified += 1 if actions: yield (new_tower, actions, len(actions)) else: print( "\tNum bad from hash:\t{}\n\tNum of blocks disqualified:\t{}\n\tNum of blocks saturated:\t{}".format( tower_state._bad_block_calls, self._num_of_blocks_disqualified, self._num_of_blocks_saturated )) return #successors.append((new_tower, actions, len(actions))) print("\tNum of desc disqualified:\t{}\n\tNum of blocks disqualified:\t{}\n\tNum of blocks saturated:\t{}".format( self._num_of_descriptors_disqualified, self._num_of_blocks_disqualified, self._num_of_blocks_saturated ))
def test_rotate(self): blocks = [] for orientation in ORIENTATIONS: blocks.append(Block(block_mesh, orientation, (0, 0, 0))) for block in blocks: self.assertEqual(list(block.get_cog()), [0, 0, 0]) if DISPLAY: for b in blocks: print (b) display([b.render() for b in blocks]) with self.assertRaises(AssertionError): Block(block_mesh, (-90, -90, -90), (0, 0, 0))
def test_spawn_block_time(self): size = 10 all_desc = [] for orientation in ORIENTATIONS: blocks = [Block(block_mesh, orientation, (i, i, 0)) for i in range(size)] o_time = 0 for block in blocks: all_desc += list(block.gen_possible_block_descriptors()) ss = time.time() for desc in all_desc: b = Block(block_mesh, desc[0], desc[1]) ee = time.time() - ss print("Time to spawn {} Blocks: {}".format(len(all_desc), ee))
def calculate_below(block: Block, blocks: List[Block]) -> Set[Block]: """ Calculated which of a given list of blocks are strictly under this given sample block. :param block: a single block with a bottom level L :param blocks: A list of blocks, all top level L-1 X - Segment of initial block S - Support blocks N - Non support blocks Front View | Side View | Top View ---------------------------------------------------------------------- XXXXXX | X | NNNNNN N S S | NNNNNN SSSSSS | | | X | | SSXSSS | | X | | SSXSSS :return: A list of 1 or more blocks that are strictly under the given block, or an empty list if no such blocks exist """ supports = set() cells = block.get_cover_cells() for potential_support in blocks: for cell in cells: # Check if this cell is above under a cell from another block if cell in potential_support.get_cover_cells(): supports.add(potential_support) break return supports
def calculate_above(block: Block, blocks: List[Block]) -> Set[Block]: """ Calculated which of a given blocks are strictly above this given sample block. :param block: a single block with a bottom level L :param block_state: A full dictionary of blocks organized by thier top levels X - Segment of initial block A - Above (Suportee) blocks N - Non above blocks Front View | Side View | Top View ---------------------------------------------------------------------- AAAAAA | A | NNNNNN N X N | NNNNNN XXXXXX | | | A | | XXAXXX | | A | | NNANNN :return: A list of 1 or more blocks that are strictly above the given block, or an empty list if no such blocks exist """ supported = set() cells = block.get_cover_cells() for potential_supported_block in blocks: for cell in cells: # Check if this cell is above under a cell from another block if cell in potential_supported_block.get_cover_cells(): supported.add(potential_supported_block) break return supported
def test_perp_tower(self): STAGE = 10 tower: Tower_State = Tower_State(size=30, ring_floor=True) for i in range(100): added = [] for father_block in tower.gen_blocks(no_floor=False): if not father_block.is_saturated(tower): for son_desc in father_block.gen_possible_block_descriptors( limit_orientation=lambda o: father_block.is_perpendicular(o), limit_len=STAGE / 2, random_order=True): son_block = Block(floor_mesh, *son_desc) if tower.can_add(son_block): tower.add(son_block) added.append(son_block) if len(added) > STAGE: break if len(added) > STAGE: break print(i) DISPLAY = False TO_FILE = True if DISPLAY or TO_FILE: old_meshes = [b.render() for b in filter(lambda b: b not in added, tower.gen_blocks())] new_meshes = [b.render() for b in added] display_colored(old_meshes + new_meshes, ['gray'] * len(old_meshes) + ['cyan'] * len(new_meshes), scale=60, to_file=TO_FILE and not DISPLAY, file_name="plots/ring_floor4/{0:03}.png".format(i) )
def test_iteration(self): tower: Tower_State = Tower_State() for new_block in [Block(block_mesh, 'flat_wide', (0, 0, i)) for i in range(1, 10)]: if tower.can_add(new_block): tower.add(new_block) for b in tower.gen_blocks(): print(b.get_top_level())
def test_str_time(self): block : Block = Block(block_mesh, (0,0,0), (0,0,0)) s = time.time() r = 3000000 for i in range(r): _ = str(block) elapse = time.time() - s print("For {}X:\t{}".format(r, elapse))
def test_cells(self): blocks = [] for i, orientation in enumerate(ORIENTATIONS): blocks.append(Block(block_mesh, orientation, ((-1)**i * i *10, (-1)**(i + 1) * i * 10, 0))) if DISPLAY: display_multiple_cells([block.get_cells() for block in blocks])
def test_hash(self): block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) block2 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) self.assertEqual(hash(block1), hash(block2)) blocks = [Block(block_mesh, (0, 0, 0), (0, 0, 0)) for _ in range(10)] for block1 in blocks: for block2 in blocks: self.assertEqual(hash(block1), hash(block2)) blocks = [Block(block_mesh, (0, 0, 0), (0, 0, 0)) for _ in range(100)] for block1 in blocks: for block2 in blocks: self.assertEqual(hash(block1), hash(block2)) for orientation in ORIENTATIONS: blocks = [Block(block_mesh, orientation, (0, 0, 0)) for _ in range(10)] for block1 in blocks: for block2 in blocks: self.assertEqual(hash(block1), hash(block2)) for orientation in ORIENTATIONS: blocks_1 = [Block(block_mesh, orientation, (10, 10, 10)) for _ in range(10)] blocks_2 = [Block(block_mesh, orientation, (10, 10, 10)) for _ in range(10)] for block1 in blocks_1: for block2 in blocks_2: self.assertEqual(hash(block1), hash(block2))
def test_sons(self): floor = RingFloor(floor_mesh, size=50) if DISPLAY: display([floor.render()]) blocks = [Block(block_mesh, *d) for d in floor.gen_possible_block_descriptors()] some = sample(blocks, 100) if DISPLAY: display([b.render() for b in some])
def test_hash_time(self): block : Block = Block(block_mesh, (0,0,0), (0,0,0)) s = time.time() r = 1000000 for i in range(r): _ = hash(block) elapse = time.time() - s print("For {}X:\t{}".format(r, elapse)) print(block.__str__())
def is_stable(tower_state, new_block: Block): """ Boolean recursive function that calculates if the new block to be places in the scheme of the current block state will stand, or topple. :param tower_state: A state of the block tower. :param new_block: potential block to add, organized in a dictionary with keys as levels and values list of blocks level -> [block1, block2, ...] :return: True iff the new arrangement still stands """ bottom_level = new_block.get_bottom_level() top_level = new_block.get_top_level() # blocks_by_top_level= tower_state.get_blocks_by_top_level() # blocks_by_bottom_level= tower_state.get_blocks_by_bottom_level() # Initiate the relation to surrounding blocks in the tower # Short-circuit the expensive calculation if can be skipped. blocks_below = calculate_below(new_block, tower_state.get_by_top(bottom_level - 1)) \ if (bottom_level - 1) in tower_state \ else set() tower_state.set_blocks_below(new_block, blocks_below) blocks_above = calculate_above(new_block, tower_state.get_by_bottom(top_level + 1)) \ if (top_level + 1) in tower_state \ else set() tower_state.set_blocks_above(new_block, blocks_above) # Last attempt to find if this situation was already stored as a unstable combination if tower_state.is_bad_block( tower_state.stringify_block_neighbors(new_block)): return False # connect the new block to the blocks above and below by making changes to their neighbor setting. tower_state.connect_block_to_neighbors(new_block) if is_stable_helper((tower_state, new_block)): return True else: # We can stringify this block's failure, contingent on it's neighbors. # This will allow to quickly check in the future if this block is stable, relative to its surroundings tower_state.add_bad_block_state(new_block) # release the relation of this block on it neighbors tower_state.disconnect_block_from_neighbors(new_block) return False
def test_perp_sons(self): floor = RingFloor(floor_mesh, size=50) blocks = [Block(block_mesh, *d) for d in floor.gen_possible_block_descriptors( limit_orientation=lambda o: floor.is_perpendicular(o))] some = sample(blocks, 100) print (floor.orientation) print (floor.is_perpendicular(floor)) if DISPLAY: display([b.render() for b in some + [floor]])
def is_overlapping(block_tower, new_block: Block): """ Check if new block clashes (physically overlaps) with the rest of the block tower :param block_tower: A tower state :param new_block: either a new object or just it's string representation :return: """ if block_tower.is_bad_block(new_block): return True bottom_level: int = new_block.get_bottom_level() top_level: int = new_block.get_top_level() """ Only scan blocks with top levels above my bottom level. X - Block. B - Bottom layer. T - Top layer XXXXXXX new block XXXXXXX others TTTTTTTT others BBBBBBB in XXXXXXXX out TTTT XXXX """ for level in filter(lambda l: l >= bottom_level, block_tower.keys()): for other_block in block_tower.get_by_top(level): """ Diqualify for overlap any block with a bottom above our top X - Block. B - Bottom layer. T - Top layer others XXXXXXXX others XXXXX in XXXXXXXX out BBBBB TTTTTTT BBBBBBBB new block XXXXXXX XXXXXXX """ if other_block.get_bottom_level( ) <= top_level and other_block.is_overlapping(new_block): # perform a memoization of bad blocks we've seen block_tower.add_bad_block(new_block) return True return False
def test_covers(self): tower: Tower_State = Tower_State() for new_block in [Block(block_mesh, 'flat_wide', (0, 0, i)) for i in range(1, 10)]: if tower.can_add(new_block): tower.add(new_block) cover = tower.get_cover_at_level(0) for i in range(10): self.assertEqual(cover, tower.get_cover_at_level(i), str(tower.get_cover_at_level(i))+str(i)) tower: Tower_State = Tower_State() for i in range(10): for j in range(i, 10 - i): new_block = Block(block_mesh, 'flat_thin', (0, j*3, i)) if tower.can_add(new_block): tower.add(new_block) if DISPLAY: display([b.render() for b in tower.gen_blocks()]) prev = 10000 for level in range(10): size = tower.get_cover_at_level(level).__len__() self.assertLessEqual(size, prev) prev = size
def test_inertia(self): block1 = Block(block_mesh, (0,0,0,), (0,0,0)) pp(block1.render().get_mass_properties()) blocks = [] for orientation in ORIENTATIONS: block1 = Block(block_mesh, orientation, (0, 0, 0)) print(orientation) pp(block1.render().get_mass_properties()) blocks.append(block1) m = combine([b.render() for b in blocks]) print("all") pp(m.get_mass_properties()) # inertia of tall tower blocks = [Block(block_mesh, 'tall_thin', (0, 0, i*15)) for i in range(1)] m = combine([b.render() for b in blocks]) print("Tall tower") pp(m.get_mass_properties()) if DISPLAY: display([m]) # inertia of wide (Y) tower blocks = [Block(block_mesh, 'short_thin', (i*15, 0, 0)) for i in range(10)] m = combine([b.render() for b in blocks]) print("inertia of wide (Y) tower") pp(m.get_mass_properties()) if DISPLAY: display([m]) # inertia of T shape tower blocks = [Block(block_mesh, 'short_thin', (0, 0, 0))] + \ [Block(block_mesh, 'flat_wide', (i, 0, 2)) for i in range(-5, 5)] m = combine([b.render() for b in blocks]) print("inertia of T shape tower") pp(m.get_mass_properties()) if DISPLAY: display([m])
def test_son_desc_time(self): result = [] size = 1000 ss = time.time() num_of_desc = 0 for orientation in ORIENTATIONS: blocks = [Block(block_mesh, orientation, (i, i, 0)) for i in range(size)] # block1 = Block(block_mesh, orientation, (0, 0, 0)) o_time = 0 for block in blocks: s = time.time() sons_dsc = list(block.gen_possible_block_descriptors()) o_time += time.time() - s num_of_desc += len(sons_dsc) result.append((orientation, o_time/size)) ee = time.time() - ss print("Time to spawn {} descriptors: {}".format(num_of_desc, ee)) pp(result)
def test_auto_close(self): block = Block(block_mesh, (0, 0, 0), (0, 0, 2)) print("block created") display([b.render() for b in [block]], auto_close=True)
def test_translate(self): block1 = Block(block_mesh, (0, 0, 0), (10, 10, 10)) self.assertEqual(list(block1.get_cog()), [10, 10, 10]) if DISPLAY: print(str(block1)) display([block1.render()])
def get_spread(self, block1: Block, block2: Block): """ Retrieves the space between two blocks that can support blocks above, should their center of gravity sit within them. Spread should only be calculated between blocks that have already been recognized as close enough to hold another block above them, otherwise behavior is not defined, or in the best case an assertion will fail. This is garanteed by only calling get_spread on blocks both directly under the same piece. Spread is commutative :param block1: :param block2: :return: """ assert block1.get_top_level() == block2.get_top_level( ), str(block1) + str(block1.get_top_level()) + str(block2) + str( block2.get_top_level()) # a spread with yourself it the cells you cover if block1 == block2: return block1.get_cover_cells() ordered_pair = (block1, block2) if block1 < block2 else (block2, block1) if ordered_pair in self._spreads_memory: # shared with father return self._spreads_memory[ordered_pair] b1_cover_x = {cell[X] for cell in block1.get_cover_cells()} b2_cover_x = {cell[X] for cell in block2.get_cover_cells()} b1_cover_y = {cell[Y] for cell in block1.get_cover_cells()} b2_cover_y = {cell[Y] for cell in block2.get_cover_cells()} inter_x = b1_cover_x & b2_cover_x inter_y = b1_cover_y & b2_cover_y spread = set() spread |= block1.get_cover_cells() spread |= block2.get_cover_cells() if (inter_x): union_y = b1_cover_y | b2_cover_y min_y = int(min(union_y)) max_y = int(max(union_y)) for y in range(min_y, max_y + 1): for x in inter_x: spread.add((x, y)) elif (inter_y): union_x = b1_cover_x | b2_cover_x min_x = int(min(union_x)) max_x = int(max(union_x)) for x in range(min_x, max_x + 1): for y in inter_y: spread.add((x, y)) else: # no common pieces - skew lines """ X XXXXXXX XXXXXXX X X or X or X XXXXXXXX X X Relevant for flat pieces only. """ pass # See if the candidate blocks above can help increase spread candidate_blocks = self.get_blocks_above( block1) & self.get_blocks_above(block2) if candidate_blocks: flat_block = candidate_blocks.pop() center_x, center_y, _ = tuple(flat_block.get_cog()) skew_center = set() for cell in spread: new_cell = ((cell[X] + center_x) // 2, (cell[Y] + center_y) // 2) skew_center.add(new_cell) spread |= skew_center self._spreads_memory[ordered_pair] = spread return spread
def test_orientation(self): block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) block2 = Block(block_mesh, 'short_wide', (0, 0, 0)) block3 = Block(block_mesh, ORIENTATION.SHORT_WIDE, (0, 0, 0)) self.assertEqual(block1.get_cells(), block2.get_cells()) self.assertEqual(block1.get_cells(), block3.get_cells()) block1 = Block(block_mesh, (90, 0, 0), (0, 0, 0)) block2 = Block(block_mesh, 'tall_wide', (0, 0, 0)) block3 = Block(block_mesh, ORIENTATION.TALL_WIDE, (0, 0, 0)) self.assertEqual(block1.get_cells(), block2.get_cells()) self.assertEqual(block1.get_cells(), block3.get_cells())
def get_successors(self, state: Tower_State): new_states = [copy(state) for _ in range(self._limit_branching)] successors = [] pp(state) for new_state in new_states: num_of_blocks_added = 0 actions = [] for father_block in state.gen_blocks(no_floor=False): if father_block.is_saturated(new_state): self._num_of_blocks_saturated += 1 continue if len(actions) > self._num_of_blocks_in_action: break son_descriptors = list(father_block.gen_possible_block_descriptors( limit_len=self._limit_sons, limit_orientation=self._son_orientation_filter, random_order=self._gen_randomly )) if self._gen_randomly: shuffle(son_descriptors) for desc in son_descriptors: if len(actions) > self._num_of_blocks_in_action: break if state.is_bad_block(Block.gen_str(desc)): self._num_of_descriptors_disqualified += 1 else: # good block description, lets try it out blocks = [Block(BLOCK_MESH, *desc)] if self._use_symmetry: sub_descriptors = Block_Search.propagate(*desc, dist=self._symmetrical_base_distance) # qualified_symmetrical_brothers = len(sub_descriptors) for sym_desc in sub_descriptors: if state.is_bad_block(Block.gen_str(desc)): self._num_of_descriptors_disqualified += 1 # qualified_symmetrical_brothers -= 1 else: blocks.append(Block(BLOCK_MESH, *sym_desc)) to_add = [] for candidate_block in blocks: if new_state.can_add(candidate_block): to_add.append(candidate_block) else: self._num_of_blocks_disqualified += 1 # else: # if self._use_symmetry: # qualified_symmetrical_brothers -= 1 if self._use_symmetry: if len(to_add) >= self._sym_son_threshold: for good_block in to_add: new_state.add(good_block) actions.append(good_block) num_of_blocks_added += 1 else: for good_block in to_add: self._num_of_blocks_disqualified += 1 new_state.disconnect_block_from_neighbors(good_block) else: for good_block in to_add: new_state.add(good_block) actions.append(good_block) num_of_blocks_added += 1 successors.append((new_state, actions, len(actions))) # if DISPLAY: # display_colored([b.render() for b in state.gen_blocks()]) # return True # print("\tNum of desc disqualified:{}\tNum of blocks disqualified:{}\tNum of staturated:{}".format( # self._num_of_descriptors_disqualified, # self._num_of_blocks_disqualified, # self._num_of_blocks_saturated # )) return successors
def test_next_block(self): # # simple block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) sons = [Block(block_mesh, orientation, position) for orientation, position in block1.gen_possible_block_descriptors()] print("All : {}".format(len(sons))) if DISPLAY: display([b.render() for b in sons + [block1] ], scale=15) # limit to type of orientation block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) for orientation in ORIENTATIONS: sons = [Block(block_mesh, orientation, position) for orientation, position in block1.gen_possible_block_descriptors(lambda o: o == orientation)] print(orientation + " : {}".format(len(sons))) if DISPLAY: display([b.render() for b in sons + [block1] ], scale=15) # all orientations around 0, 0, 0 for orientation in ORIENTATIONS: block1 = Block(block_mesh, orientation, (0, 0, 0)) for orientation in ORIENTATIONS: sons = [Block(block_mesh, orientation, position) for orientation, position in block1.gen_possible_block_descriptors(lambda o: o == orientation)] print(orientation + " : {}".format(len(sons))) if DISPLAY: display([b.render() for b in sons + [block1] ], scale=15) # all orientations around 1, 1, 0 for base_orientation in ORIENTATIONS: print("Base orientation : {}".format(base_orientation)) block1 = Block(block_mesh, base_orientation, (1, 1, 0)) for son_orientation in ORIENTATIONS: sons = list(block1.gen_possible_block_descriptors(lambda o: o == son_orientation)) print("\t" + son_orientation + " : {}".format(len(sons))) if DISPLAY: display([b.render() for b in sons + [block1] ], scale=15)
def test_constructor(self): block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) self.assertEqual(list(block1.get_cog()), [0, 0, 0]) if DISPLAY: print(str(block1)) display([block1.render()])
def test_spread(self): tower_state = Tower_State() #same orientation orientation = 'tall_wide' block1 = Block(block_mesh, orientation, (0, 0, 0)) block2 = Block(block_mesh, orientation, (2, 1, 0)) spread = tower_state.get_spread(block1, block2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) orientation = 'short_wide' block1 = Block(block_mesh, orientation, (0, 0, 0)) block2 = Block(block_mesh, orientation, (5, 5, 0)) spread = tower_state.get_spread(block1, block2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) orientation = 'flat_thin' block1 = Block(block_mesh, orientation, ( 0, 0, 0)) block2 = Block(block_mesh, orientation, (10, 10, 0)) spread = tower_state.get_spread(block1, block2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) # differing orientations - must have same top level block1 = Block(block_mesh, 'flat_wide', ( 0, 0, 0)) block2 = Block(block_mesh, 'tall_thin', ( 5, 3, -7)) spread = tower_state.get_spread(block1, block2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) block1 = Block(block_mesh, 'flat_wide', ( 0, 0, 1)) block2 = Block(block_mesh, 'short_thin', ( -10, 3, 0)) spread = tower_state.get_spread(block1, block2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) # test commutative quality of spread: ie. my spread with you is the same as yours spread with me. block1 = Block(block_mesh, 'flat_wide', ( 0, 0, 1)) block2 = Block(block_mesh, 'short_thin', ( -15, 5, 0)) spread1 = tower_state.get_spread(block1, block2) spread2 = tower_state.get_spread(block2, block1) self.assertEqual(spread1, spread2) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread1, spread2], scale=20) block1 = Block(block_mesh, (0, 0, 0), (0, 5, 1)) block2 = Block(block_mesh, (0, 0, 0), (-2, -11, 1)) block3 = Block(block_mesh, 'flat_wide', (-1, -6, 3)) tower_state.set_blocks_above(block1, {block3}) tower_state.set_blocks_above(block2, {block3}) spread = tower_state.get_spread(block2, block1) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) block1 = Block(block_mesh, (0, 0, 0), (0, 9, 1)) block2 = Block(block_mesh, (0, 0, 0), (-2, -13, 1)) block3 = Block(block_mesh, 'flat_wide', (-1, -6, 3)) tower_state.set_blocks_above(block1, {block3}) tower_state.set_blocks_above(block2, {block3}) spread = tower_state.get_spread(block2, block1) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20) block1 = Block(block_mesh, 'short_thin', (-8, -1, 1)) block2 = Block(block_mesh, 'short_thin', (7, 1, 1)) block3 = Block(block_mesh, 'flat_wide', (0, 0, 3)) tower_state.set_blocks_above(block1, {block3}) tower_state.set_blocks_above(block2, {block3}) spread = tower_state.get_spread(block2, block1) if DISPLAY: display([block1.render(), block2.render()]) display_multiple_cells([block1.get_cells(), block2.get_cells()], scale=20) display_multiple_grids([block1.get_cover_cells(), block2.get_cover_cells(), spread], scale=20)
def test_overlap(self): block1 = Block(block_mesh, (0, 0, 0), (0, 0, 0)) #Overlapping overlapping_blocks = [] overlapping_blocks.append(Block(block_mesh, (0, 0, 0), (0, 0, 0))) # 0 overlapping_blocks.append(Block(block_mesh, (90, 90, 0), (0, 0, 1))) # 1 overlapping_blocks.append(Block(block_mesh, (90, 0, 0), (0, 7, 0))) # 2 overlapping_blocks.append(Block(block_mesh, (90, 0, 0), (0, -7, 0))) # 3 overlapping_blocks.append(Block(block_mesh, (90, 0, 0), (0, 0, 0))) # 4 for i, block in enumerate(overlapping_blocks): if DISPLAY: display([b.render() for b in [block1, block]]) display_multiple_cells([b.get_cells() for b in [block1, block]], scale=10) self.assertTrue(block1.is_overlapping(block), "Block {} found not to be overlapping! Joint cells:{}".format(i, str(block.get_cells() & block1.get_cells()))) if DISPLAY: display([b.render() for b in [block1] + overlapping_blocks]) #Non- Overlapping not_overlapping_blocks = [] not_overlapping_blocks.append(Block(block_mesh, (0, 0, 0), (30, 0, 0))) # 0 not_overlapping_blocks.append(Block(block_mesh, (0, 0, 0), (0, 0, 10))) # 1 not_overlapping_blocks.append(Block(block_mesh, (0, 0, 0), (0, 0, 5))) # 2 not_overlapping_blocks.append(Block(block_mesh, (90, 90, 0),(0, 0, 2))) # 3 for i, block in enumerate(not_overlapping_blocks): if DISPLAY: display([b.render() for b in [block1, block]]) display_multiple_cells([b.get_cells() for b in [block1, block]], scale=10) self.assertTrue(not block1.is_overlapping(block), "Block {} found to be overlapping!\n Joint cells:{}".format(i, str(block.get_cells() & block1.get_cells()))) if DISPLAY: display([b.render() for b in [block1] + not_overlapping_blocks])