def test_rectangle_creation_with_defaults(): """Test creating rectangle with defaults.""" rectangle = Rectangle(width=5, height=6) assert rectangle.width == 5 assert rectangle.height == 6 assert rectangle.x == 0 assert rectangle.y == 0
def _generate_rooms(self): """A function to generate random rooms.""" for _ in range(self._room_attempts): # Get Random Dimensions for New Room x = random.randint(1, self._width - 1) y = random.randint(1, self._height - 1) room_width = random.randint(self._min_room_width, self._max_room_width) room_height = random.randint(self._min_room_height, self._max_room_height) new_room = Rectangle(width=room_width, height=room_height, x=x, y=y) # Make sure the room doesn't overlap other rooms overlaps = False for room in self.rooms: if room.overlaps(new_room): overlaps = True break in_dungeon = False if not (not self._dungeon_rectangle.contains( new_room.x, new_room.y) or not self._dungeon_rectangle.contains( new_room.x_max, new_room.y_max)): in_dungeon = True if not overlaps and in_dungeon: self.rooms.append(new_room) # Add Rooms to Dungeons for room in self.rooms: for x in range(room.x, room.x + room.width): for y in range(room.y, room.y + room.height): self._set_dungeon_cell(x, y, self.DUNGEON_ROOM)
def test_rectangle_creation(): """Test creating rectangle with x and y set.""" rectangle = Rectangle(width=5, height=6, x=1, y=4) assert rectangle.width == 5 assert rectangle.height == 6 assert rectangle.x == 1 assert rectangle.y == 4
def __init__(self, width, height, random_seed=None, room_attempts=100, max_room_width=10, max_room_height=10, min_room_width=5, min_room_height=5, randomness=0.5): """The __init__ function for the Dungeon class.""" self._width = width self._height = height self._room_attempts = room_attempts self._max_room_width = max_room_width self._min_room_width = min_room_width self._max_room_height = max_room_height self._min_room_height = min_room_height self.dungeon = [] # This is in the form dungeon[y][x] self._randomness = randomness self._dungeon_rectangle = Rectangle(width=self._width, height=self._height) self.rooms = [] if random_seed is not None: random.seed(random_seed) # Fill the Dungeon Array for _ in range(self._height): row = [self.DUNGEON_WALL for _ in range(self._width)] self.dungeon.append(row) # Add Rooms self._generate_rooms() # Add Passages self._carve_passages() self._open_rooms() # Remove Dead Ends self._remove_dead_ends()
def test_rectangles_same(): """Test two rectangles are equal if they are the same.""" rectangle_1 = Rectangle(width=5, height=5, x=0, y=0) assert rectangle_1 == rectangle_1
def test_x_max(): """Test getting the rectangles x_max.""" rectangle = Rectangle(width=6, height=4, x=1, y=2) assert rectangle.x_max == 7
def test_rectangle_size(): """Test getting the rectangles size.""" rectangle = Rectangle(width=6, height=4) assert rectangle.size == (6, 4) # (width, height)
def test_rectangle_position(): """Test getting the rectangles position.""" rectangle = Rectangle(width=5, height=6, x=1, y=2) assert rectangle.position == (1, 2) # (x, y)
def test_rectangle_center(): """Test getting the rectangles center.""" rectangle = Rectangle(width=4, height=7, x=5, y=7) assert rectangle.center == (7, 10.5) # ( (x1+x2)/2, (y1+y2)/2 )
def test_rectangle_center_with_defaults(): """Test getting the rectangles center with defaults.""" rectangle = Rectangle(width=6, height=5) assert rectangle.center == (3, 2.5) # ( (x1+x2)/2, (y1+y2)/2 )
class Dungeon(object): """A class to contain all the information about a dungeon that will be generated.""" DUNGEON_ROOM = ' ' DUNGEON_HALL = '*' DUNGEON_WALL = 'X' DUNGEON_DOORWAY = '$' def __init__(self, width, height, random_seed=None, room_attempts=100, max_room_width=10, max_room_height=10, min_room_width=5, min_room_height=5, randomness=0.5): """The __init__ function for the Dungeon class.""" self._width = width self._height = height self._room_attempts = room_attempts self._max_room_width = max_room_width self._min_room_width = min_room_width self._max_room_height = max_room_height self._min_room_height = min_room_height self.dungeon = [] # This is in the form dungeon[y][x] self._randomness = randomness self._dungeon_rectangle = Rectangle(width=self._width, height=self._height) self.rooms = [] if random_seed is not None: random.seed(random_seed) # Fill the Dungeon Array for _ in range(self._height): row = [self.DUNGEON_WALL for _ in range(self._width)] self.dungeon.append(row) # Add Rooms self._generate_rooms() # Add Passages self._carve_passages() self._open_rooms() # Remove Dead Ends self._remove_dead_ends() @property def width(self): """The width of the dungeon.""" return self._width @property def height(self): """The height of the dungeon.""" return self._height @property def randomness(self): """The randomness of the dungeon passages.""" if self._randomness > 1: return 1 if self._randomness < 0: return 0 return self._randomness def _set_dungeon_cell(self, x, y, value): """A function to set the value of a specified dungeon cell. Args: x: The specified x coordinate. y: The specified y coordinate. value: The new value of the cell. """ self.dungeon[y][x] = value def _get_dungeon_cell(self, x, y): """A function to get the value of a specified dungeon cell.""" return self.dungeon[y][x] def _generate_rooms(self): """A function to generate random rooms.""" for _ in range(self._room_attempts): # Get Random Dimensions for New Room x = random.randint(1, self._width - 1) y = random.randint(1, self._height - 1) room_width = random.randint(self._min_room_width, self._max_room_width) room_height = random.randint(self._min_room_height, self._max_room_height) new_room = Rectangle(width=room_width, height=room_height, x=x, y=y) # Make sure the room doesn't overlap other rooms overlaps = False for room in self.rooms: if room.overlaps(new_room): overlaps = True break in_dungeon = False if not (not self._dungeon_rectangle.contains( new_room.x, new_room.y) or not self._dungeon_rectangle.contains( new_room.x_max, new_room.y_max)): in_dungeon = True if not overlaps and in_dungeon: self.rooms.append(new_room) # Add Rooms to Dungeons for room in self.rooms: for x in range(room.x, room.x + room.width): for y in range(room.y, room.y + room.height): self._set_dungeon_cell(x, y, self.DUNGEON_ROOM) def _carve_passages(self): """A function to carve passages in the maze.""" # Loop through the dungeon to create maze. for y in range(1, self._height): for x in range(1, self._width): self._carve_passage_helper(x, y) def _carve_passage_helper(self, start_x, start_y, last_direction=None): """A helper for carving the dungeon passages. Args: start_x: the starting x coordinate for the passageway. start_y: the starting y coordinate for the passageway. last_direction: the last direction a passage was carved. """ # Check if the cell can be carved if not self._can_carve_passage(start_x, start_y, last_direction): return # Carve the current cell self._set_dungeon_cell(start_x, start_y, self.DUNGEON_HALL) available_directions = [ direction for direction in directions.DPAD_DIRECTIONS if self._can_carve_passage(start_x + direction.x, start_y + direction.y, direction) ] # Pick a new direction while len(available_directions) > 0: change_direction = random.random() < self._randomness if last_direction not in available_directions: change_direction = True new_direction = last_direction if change_direction or new_direction is None: new_direction_index = random.randint( 0, len(available_directions) - 1) new_direction = available_directions[new_direction_index] available_directions.remove(new_direction) self._carve_passage_helper(start_x + new_direction.x, start_y + new_direction.y, new_direction) def _can_carve_passage(self, x, y, incoming_direction=None): """Determine if a passage can be carved at a specified location in the dungeon. Args: x: the x coordinate of the cell to check y: the y coordinate of the cell to check incoming_direction: The direction that the passage has been moving. Returns: True if the cell can be carved, or false if it cannot. """ # Make sure the section is a wall if not self._get_dungeon_cell(x, y) == self.DUNGEON_WALL: return False # Check surrounding cells for direction in directions.CARDINAL_DIRECTIONS: # Check the coordinates are in the dungeon if not self._dungeon_rectangle.contains(x + direction.x, y + direction.y): return False # We can ignore cells behind us. if incoming_direction is not None: if incoming_direction.y == directions.UP.y or incoming_direction.y == directions.DOWN.y: if incoming_direction.y * -1 == direction.y: continue if incoming_direction.x == directions.LEFT.x or incoming_direction.x == directions.RIGHT.x: if incoming_direction.x * -1 == direction.x: continue # Check the coordinates are a wall if not self._get_dungeon_cell( x + direction.x, y + direction.y) == self.DUNGEON_WALL: return False return True def _open_rooms(self): """A function to open the rooms to the passageways.""" # Loop Through Rooms for room in self.rooms: possible_directions = [x for x in directions.DPAD_DIRECTIONS] multiple_openings = random.random() > 0.75 has_opening = False while len(possible_directions) > 0: direction = possible_directions[random.randint( 0, len(possible_directions) - 1)] possible_directions.remove(direction) possible_locations = [] if direction == directions.UP: possible_locations = [ (x, room.y_min - 1) for x in range(room.x_min, room.x_max) ] elif direction == directions.DOWN: possible_locations = [ (x, room.y_max) for x in range(room.x_min, room.x_max) ] elif direction == directions.LEFT: possible_locations = [ (room.x_min - 1, y) for y in range(room.y_min, room.y_max) ] elif direction == directions.RIGHT: possible_locations = [ (room.x_max, y) for y in range(room.y_min, room.y_max) ] # Loop through random locations till you find one that can be opened. while len(possible_locations) > 0: location = possible_locations[random.randint( 0, len(possible_locations) - 1)] possible_locations.remove(location) if self._can_carve_entry(location[0], location[1], direction): self._set_dungeon_cell(location[0], location[1], self.DUNGEON_DOORWAY) has_opening = True break # Break if done if has_opening and not multiple_openings: break def _can_carve_entry(self, x, y, incoming_direction): # Is the cell I am trying to change a wall if self._get_dungeon_cell(x, y) != self.DUNGEON_WALL: return False # Is the next cell in the rectangle if not self._dungeon_rectangle.contains(x + incoming_direction.x, y + incoming_direction.y): return False # Does the room I am trying to change connect to a room or hall? if not self._get_dungeon_cell(x + incoming_direction.x, y + incoming_direction.y) == self.DUNGEON_HALL and \ not self._get_dungeon_cell(x + incoming_direction.x, y + incoming_direction.y) == self.DUNGEON_ROOM: return False if incoming_direction == directions.UP or incoming_direction == directions.DOWN: if not self._get_dungeon_cell(x - 1, y) == self.DUNGEON_WALL or \ not self._get_dungeon_cell(x + 1, y) == self.DUNGEON_WALL: return False if incoming_direction == directions.LEFT or incoming_direction == directions.RIGHT: if not self._get_dungeon_cell(x, y - 1) == self.DUNGEON_WALL or \ not self._get_dungeon_cell(x, y + 1) == self.DUNGEON_WALL: return False return True def _remove_dead_ends(self): """Remove maze dead ends.""" for y in range(0, self._height): for x in range(0, self._width): self._remove_dead_ends_helper(x, y) def _remove_dead_ends_helper(self, x, y): cell = self._get_dungeon_cell(x, y) if cell == self.DUNGEON_HALL: d_pad_directions = [x for x in directions.DPAD_DIRECTIONS] connections = [] for direction in d_pad_directions: connected_cell = self._get_dungeon_cell( x + direction.x, y + direction.y) if connected_cell in [ self.DUNGEON_HALL, self.DUNGEON_DOORWAY, self.DUNGEON_ROOM ]: connections.append((x + direction.x, y + direction.y)) if len(connections) <= 1: self._set_dungeon_cell(x, y, self.DUNGEON_WALL) if len(connections) == 1: self._remove_dead_ends_helper(connections[0][0], connections[0][1]) def print_dungeon(self): """A function to print the dungeon to standard out.""" # Print Room in dungeon for y in range(0, self._height): for x in range(0, self._width): print(self._get_dungeon_cell(x, y), end='') print('')
def test_rectangle_does_not_contains(): """Test the rectangle can determine a point is not contained.""" rectangle = Rectangle(width=4, height=5, x=2, y=1) contains = rectangle.contains(x=-4, y=3) assert contains is False
def test_y_min(): """Test getting the rectangles y_min.""" rectangle = Rectangle(width=6, height=4, x=1, y=2) assert rectangle.y_min == 2
def test_rectangles_not_equal(): """Test two rectangles are not equal.""" rectangle_1 = Rectangle(width=5, height=5, x=0, y=0) rectangle_2 = Rectangle(width=5, height=6, x=0, y=0) assert not rectangle_1 == rectangle_2
def test_rectangles_does_not_overlap(): """Test the rectangle can detect it does not overlap.""" rectangle_1 = Rectangle(width=5, height=5, x=0, y=0) rectangle_2 = Rectangle(width=5, height=5, x=10, y=9) overlaps = rectangle_1.overlaps(rectangle_2) assert overlaps is False
def test_rectangle_overlaps_can_touch_below(): """Test the rectangle can detect overlaps even if just touching.""" rectangle_1 = Rectangle(width=10, height=10, x=0, y=0) rectangle_2 = Rectangle(width=10, height=10, x=9, y=10) overlaps = rectangle_1.overlaps(rectangle_2, can_touch=True) assert overlaps is False
def test_rectangle_overlaps_touches(): """Test the rectangle can detect overlaps even if just touching.""" rectangle_1 = Rectangle(width=10, height=10, x=0, y=0) rectangle_2 = Rectangle(width=10, height=10, x=10, y=9) overlaps = rectangle_1.overlaps(rectangle_2) assert overlaps is True
def test_rectangles_does_not_overlap_above(): """Test the rectangle can determine if it overlaps another.""" rectangle_1 = Rectangle(width=10, height=10, x=0, y=0) rectangle_2 = Rectangle(width=5, height=5, x=2, y=-6) overlaps = rectangle_1.overlaps(rectangle_2) assert overlaps is False
def test_rectangle_contains(): """Test the rectangle can find a containing point.""" rectangle = Rectangle(width=4, height=5, x=2, y=1) contains = rectangle.contains(x=3, y=3) assert contains is True
def test_rectangles_not_equal_different_type(): """Test rectangle doesn't match different type.""" rectangle_1 = Rectangle(width=5, height=5, x=0, y=0) assert not rectangle_1 == 1
def test_rectangles_overlap(): """Test the rectangle can determine if it overlaps another.""" rectangle_1 = Rectangle(width=5, height=5, x=0, y=0) rectangle_2 = Rectangle(width=5, height=5, x=2, y=2) overlaps = rectangle_1.overlaps(rectangle_2) assert overlaps is True
def test_rectangle_area(): """Test getting the rectangles area.""" rectangle = Rectangle(width=4, height=5) assert rectangle.area == 20 # 20 = 4 * 5