Exemple #1
0
	def get_ground_units(self, position=None, radius=None):
		"""@see get_ships"""
		if position is not None and radius is not None:
			circle = Circle(position, radius)
			return [unit for unit in self.ground_units if circle.contains(unit.position)]
		else:
			return self.ground_units
Exemple #2
0
	def testCircle(self):
		c1 = Circle(Point(0,0), 1)
		c2 = Circle(Point(0,0), 2)
		c3 = Circle(Point(0,0), 0)
		self.assertFalse(c1 == c2)
		self.assertTrue(c1 != c2)
		self.assertNotEqual(c1, c2)
		self.assertEqual(c1.get_coordinates(), [(-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)])
		self.assertEqual(c3.get_coordinates(), [(0,0)])
Exemple #3
0
	def get_ground_units(self, position=None, radius=None):
		"""@see get_ships"""
		if position is not None and radius is not None:
			circle = Circle(position, radius)
			units = []
			for unit in self.ground_units:
				if circle.contains(unit.position):
					units.append(unit)
			return units
		else:
			return self.ground_units
Exemple #4
0
	def get_buildings(self, position=None, radius=None):
		"""@see get_ships"""
		buildings = []
		if position is not None and radius is not None:
			circle = Circle(position, radius)
			for island in self.islands:
				for building in island.buildings:
					if circle.contains(building.position.center()):
						buildings.append(building)
			return buildings
		else:
			return [b for b in island.buildings for island in self.islands]
Exemple #5
0
	def get_random_location(self, in_range):
		"""Returns a random location in walking_range, that we can find a path to
		@param in_range: int, max distance to returned point from current position
		@return: Instance of Point or None"""
		possible_walk_targets = Circle(self.position, in_range).get_coordinates()
		possible_walk_targets.remove(self.position.to_tuple())
		self.session.random.shuffle(possible_walk_targets)
		for coord in possible_walk_targets:
			target = Point(*coord)
			if self.check_move(target):
				return target
		return None
Exemple #6
0
	def get_ships(self, position=None, radius=None):
		"""Returns all ships on the map, optionally only those in range
		around the specified position.
		@param position: Point or Rect instance.
		@param radius: int radius to use.
		@return: List of ships.
		"""
		if position is not None and radius is not None:
			circle = Circle(position, radius)
			return [ship for ship in self.ships if circle.contains(ship.position)]
		else:
			return self.ships
    def get_random_location(self, in_range):
        """Returns a random location in walking_range, that we can find a path to
		@param in_range: int, max distance to returned point from current position
		@return: Instance of Point or None"""
        possible_walk_targets = Circle(self.position,
                                       in_range).get_coordinates()
        possible_walk_targets.remove(self.position.to_tuple())
        self.session.random.shuffle(possible_walk_targets)
        for coord in possible_walk_targets:
            target = Point(*coord)
            if self.check_move(target):
                return target
        return None
    def send_ship_random_branch(self, ship, branch_office=None):
        """Sends a ship to a random branch office on the map
		@param ship: Ship instance that is to be used
		@param branch_office: Branch Office instance to move to. Random one is selected on None."""
        self.log.debug("Trader %s ship %s moving to bo (random=%s)", self.worldid, ship.worldid, \
                       (branch_office is None))
        # maybe this kind of list should be saved somewhere, as this is pretty performance intense
        branchoffices = self.session.world.get_branch_offices()
        if len(branchoffices) == 0:
            # there aren't any branch offices, so move randomly
            self.send_ship_random(ship)
        else:
            # select a branch office
            if branch_office is None:
                rand = self.session.random.randint(0, len(branchoffices) - 1)
                self.office[ship.worldid] = branchoffices[rand]
            else:
                self.office[ship.worldid] = branch_office
            found_path_to_bo = False
            # try to find a possible position near the bo
            for point in Circle(self.office[ship.worldid].position.center(),
                                ship.radius):
                try:
                    ship.move(point, Callback(self.reached_branch, ship))
                except MoveNotPossible:
                    continue
                found_path_to_bo = True
                self.ships[ship] = self.shipStates.moving_to_branch
                break
            if not found_path_to_bo:
                self.send_ship_random(ship)
Exemple #9
0
    def get_ships(self, position=None, radius=None):
        """Returns all ships on the map. Optionally only those in range
		around the specified position.
		@param position: Point or Rect instance.
		@param radius: int radius to use.
		@return: List of ships.
		"""
        if position is not None and radius is not None:
            circle = Circle(position, radius)
            ships = []
            for ship in self.ships:
                if circle.contains(ship.position):
                    ships.append(ship)
            return ships
        else:
            return self.ships
Exemple #10
0
    def get_surrounding_tiles(self, point, radius=1):
        """Returns tiles around point with specified radius.
		@param point: instance of Point"""
        for position in Circle(point, radius):
            tile = self.get_tile(position)
            if tile is not None:
                yield tile
Exemple #11
0
	def testCircle(self):
		c1 = Circle(Point(0,0), 1)
		c2 = Circle(Point(0,0), 2)
		c3 = Circle(Point(0,0), 0)
		self.assertFalse(c1 == c2)
		self.assertTrue(c1 != c2)
		self.assertNotEqual(c1, c2)
		self.assertEqual(c1.get_coordinates(), [(-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)])
		self.assertEqual(c3.get_coordinates(), [(0,0)])
Exemple #12
0
    def get_tiles_in_radius(self, position, radius, shuffle=False):
        """Returns a all tiles in the radius around the point.
		This is a generator, make sure you use it appropriately.
		@param position: Point instance
		@return List of tiles in radius.
		"""
        assert isinstance(position, Point)
        points = Circle(position, radius)
        if shuffle:
            points = list(points)
            self.session.random.shuffle(points)
        for point in points:
            if self.map_dimensions.contains_without_border(point):
                # don't yield if point is not in map, those points don't exist
                yield self.get_tile(point)
Exemple #13
0
    def move_to_next_route_bo(self):
        next_destination = self.get_next_destination()
        if next_destination == None:
            return
        branch_office = next_destination['branch_office']
        found_path_to_bo = False

        for point in Circle(branch_office.position.center(), self.ship.radius):
            try:
                self.ship.move(point, self.on_route_bo_reached)
            except MoveNotPossible:
                continue
            found_path_to_bo = True
            break
        if not found_path_to_bo:
            self.disable()
Exemple #14
0
    def go(self, x, y):
        """Moves the ship.
		This is called when a ship is selected and RMB is pressed outside the ship"""
        self.stop()

        #disable the trading route
        if hasattr(self, 'route'):
            self.route.disable()
        ship_id = self.worldid  # this has to happen here,

        # cause a reference to self in a temporary function is implemented
        # as a hard reference, which causes a memory leak
        def tmp():
            if self.session.world.player == self.owner:
                self.session.view.renderer['GenericRenderer'].removeAll(
                    "buoy_" + str(ship_id))

        tmp()
        move_target = Point(int(round(x)), int(round(y)))
        try:
            self.move(move_target, tmp)
        except MoveNotPossible:
            # find a near tile to move to
            target_found = False
            surrounding = Circle(move_target, radius=0)
            while not target_found and surrounding.radius < 4:
                surrounding.radius += 1
                for move_target in surrounding:
                    try:
                        self.move(move_target, tmp)
                    except MoveNotPossible:
                        continue
                    target_found = True
                    break
        if self.session.world.player == self.owner:
            if self.position.x != move_target.x or self.position.y != move_target.y:
                move_target = self.get_move_target()
            if move_target is not None:
                loc = fife.Location(self.session.view.layers[LAYERS.OBJECTS])
                loc.thisown = 0
                coords = fife.ModelCoordinate(move_target.x, move_target.y)
                coords.thisown = 0
                loc.setLayerCoordinates(coords)
                self.session.view.renderer['GenericRenderer'].addAnimation(
                    "buoy_" + str(self.worldid), fife.GenericRendererNode(loc),
                    horizons.main.fife.animationpool.addResourceFromFile(
                        "as_buoy0-idle-45"))
Exemple #15
0
    def move_to_next_route_bo(self, advance_waypoint=True):
        next_destination = self.get_next_destination(advance_waypoint)
        if next_destination == None:
            return

        branch_office = next_destination['branch_office']
        if self.ship.position.distance_to_point(
                branch_office.position.center()) <= self.ship.radius:
            self.on_route_bo_reached()
            return

        try:
            self.ship.move(Circle(branch_office.position.center(),
                                  self.ship.radius),
                           self.on_route_bo_reached,
                           blocked_callback=self.on_ship_blocked)
        except MoveNotPossible:
            # retry in 5 seconds
            Scheduler().add_new_object(self.on_ship_blocked, self,
                                       GAME_SPEED.TICKS_PER_SECOND * 5)
Exemple #16
0
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	The coordinates of tiles will be 0 <= x < width and 0 <= y < height
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_set = set()

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island
    # creation_method 2 - a number of randomly sized and placed islands

    # place this number of shapes
    for i in xrange(15 + width * height / 45):
        # place shape determined by shape_id on (x, y)
        add = True
        rect_chance = 6
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)
        elif creation_method == 2:
            shape_id = rand.randint(2, 8)
            rect_chance = 29
            if rand.randint(0, 4) == 0:
                rect_chance = 13
                add = False

        shape = None
        if rand.randint(1, rect_chance) == 1:
            # use a rect
            if add:
                x = rand.randint(8, width - 7)
                y = rand.randint(8, height - 7)
                if creation_method == 0:
                    shape = Rect.init_from_topleft_and_size(x - 3, y - 3, 5, 5)
                elif creation_method == 1:
                    shape = Rect.init_from_topleft_and_size(x - 5, y - 5, 8, 8)
                elif creation_method == 2:
                    shape = Rect.init_from_topleft_and_size(
                        x - 5, y - 5, rand.randint(2, 8), rand.randint(2, 8))
            else:
                x = rand.randint(0, width)
                y = rand.randint(0, height)
                shape = Rect.init_from_topleft_and_size(
                    x - 5, y - 5, rand.randint(2, 8), rand.randint(2, 8))
        else:
            # use a circle, where radius is determined by shape_id
            radius = shape_id
            if not add and rand.randint(0, 6) < 5:
                x = rand.randint(-radius * 3 / 2, width + radius * 3 / 2)
                y = rand.randint(-radius * 3 / 2, height + radius * 3 / 2)
                shape = Circle(Point(x, y), shape_id)
            elif width - radius - 4 >= radius + 3 and height - radius - 4 >= radius + 3:
                x = rand.randint(radius + 3, width - radius - 4)
                y = rand.randint(radius + 3, height - radius - 4)
                shape = Circle(Point(x, y), shape_id)

        if shape:
            for shape_coord in shape.tuple_iter():
                if add:
                    map_set.add(shape_coord)
                elif shape_coord in map_set:
                    map_set.discard(shape_coord)

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # add grass tiles
    for x, y in map_set:
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, GROUND.DEFAULT_LAND)

    def fill_tiny_spaces(tile):
        """Fills 1 tile gulfs and straits with the specified tile
		@param tile: ground tile to fill with
		"""

        all_neighbours = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1),
                          (1, 0), (1, 1)]
        neighbours = [(-1, 0), (0, -1), (0, 1), (1, 0)]
        corners = [(-1, -1), (-1, 1)]
        knight_moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2),
                        (2, -1), (2, 1)]
        bad_configs = set([
            0, 1 << 0, 1 << 1, 1 << 2, 1 << 3, (1 << 0) | (1 << 3),
            (1 << 1) | (1 << 2)
        ])

        edge_set = copy.copy(map_set)
        reduce_edge_set = True

        while True:
            to_fill = set()
            to_ignore = set()
            for x, y in edge_set:
                # ignore the tiles with no empty neighbours
                if reduce_edge_set:
                    is_edge = False
                    for x_offset, y_offset in all_neighbours:
                        if (x + x_offset, y + y_offset) not in map_set:
                            is_edge = True
                            break
                    if not is_edge:
                        to_ignore.add((x, y))
                        continue

                for x_offset, y_offset in neighbours:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) in map_set:
                        continue
                    # (x2, y2) is now a point just off the island

                    neighbours_dirs = 0
                    for i in xrange(len(neighbours)):
                        x3 = x2 + neighbours[i][0]
                        y3 = y2 + neighbours[i][1]
                        if (x3, y3) not in map_set:
                            neighbours_dirs |= (1 << i)
                    if neighbours_dirs in bad_configs:
                        # part of a straight 1 tile gulf
                        to_fill.add((x2, y2))
                    else:
                        for x_offset, y_offset in corners:
                            x3 = x2 + x_offset
                            y3 = y2 + y_offset
                            x4 = x2 - x_offset
                            y4 = y2 - y_offset
                            if (x3, y3) in map_set and (x4, y4) in map_set:
                                # part of a diagonal 1 tile gulf
                                to_fill.add((x2, y2))
                                break

                # block 1 tile straits
                for x_offset, y_offset in knight_moves:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) not in map_set:
                        continue
                    if abs(x_offset) == 1:
                        y2 = y + y_offset / 2
                        if (x2, y2) in map_set or (x, y2) in map_set:
                            continue
                    else:
                        x2 = x + x_offset / 2
                        if (x2, y2) in map_set or (x2, y) in map_set:
                            continue
                    to_fill.add((x2, y2))

                # block diagonal 1 tile straits
                for x_offset, y_offset in corners:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    x3 = x + 2 * x_offset
                    y3 = y + 2 * y_offset
                    if (x2, y2) not in map_set and (x3, y3) in map_set:
                        to_fill.add((x2, y2))
                    elif (x2, y2) in map_set and (x2, y) not in map_set and (
                            x, y2) not in map_set:
                        to_fill.add((x2, y))

            if to_fill:
                for x, y in to_fill:
                    map_set.add((x, y))
                    map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

                old_size = len(edge_set)
                edge_set = edge_set.difference(to_ignore).union(to_fill)
                reduce_edge_set = old_size - len(edge_set) > 50
            else:
                break

    # possible movement directions
    all_moves = {
        'sw': (-1, -1),
        'w': (-1, 0),
        'nw': (-1, 1),
        's': (0, -1),
        'n': (0, 1),
        'se': (1, -1),
        'e': (1, 0),
        'ne': (1, 1)
    }

    def get_island_outline():
        """
		@return: the points just off the island as a dict
		"""
        result = set()
        for x, y in map_set:
            for offset_x, offset_y in all_moves.itervalues():
                coords = (x + offset_x, y + offset_y)
                if coords not in map_set:
                    result.add(coords)
        return result

    # add grass to sand tiles
    fill_tiny_spaces(GROUND.DEFAULT_LAND)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.SAND_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.SAND_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.SAND_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.SAND_NORTH
        # sandy corner
        elif filled == ['se']:
            tile = GROUND.SAND_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.SAND_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.SAND_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.SAND_NORTHEAST1
        # grassy corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.SAND_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.SAND_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.SAND_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.SAND_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
    map_set = map_set.union(outline)

    # add sand to shallow water tiles
    fill_tiny_spaces(GROUND.SAND)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.COAST_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.COAST_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.COAST_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.COAST_NORTH
        # mostly wet corner
        elif filled == ['se']:
            tile = GROUND.COAST_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.COAST_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.COAST_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.COAST_NORTHEAST1
        # mostly dry corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.COAST_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.COAST_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.COAST_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.COAST_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
    map_set = map_set.union(outline)

    # add shallow water to deep water tiles
    fill_tiny_spaces(GROUND.SHALLOW_WATER)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.DEEP_WATER_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.DEEP_WATER_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.DEEP_WATER_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.DEEP_WATER_NORTH
        # mostly deep corner
        elif filled == ['se']:
            tile = GROUND.DEEP_WATER_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.DEEP_WATER_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.DEEP_WATER_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.DEEP_WATER_NORTHEAST1
        # mostly shallow corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    map_db("COMMIT")
    return map_db
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_dict = {}

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island

    # place this number of shapes
    for i in xrange(int(float(width + height) / 2 * 1.5)):
        x = rand.randint(8, width - 8)
        y = rand.randint(8, height - 8)

        # place shape determined by shape_id on (x, y)
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)

        if rand.randint(1, 4) == 1:
            # use a rect
            if creation_method == 0:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 3, y - 3, 5, 5).tuple_iter():
                    map_dict[shape_coord] = True
            elif creation_method == 1:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 5, y - 5, 8, 8).tuple_iter():
                    map_dict[shape_coord] = True

        else:
            # use a circle, where radius is determined by shape_id
            for shape_coord in Circle(Point(x, y), shape_id).tuple_iter():
                map_dict[shape_coord] = True

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # add grass tiles
    for x, y in map_dict.iterkeys():
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, GROUND.DEFAULT_LAND)

    def fill_tiny_spaces(tile):
        """Fills 1 tile gulfs and straits with the specified tile
		@param tile: ground tile to fill with
		"""

        neighbours = [(-1, 0), (0, -1), (0, 1), (1, 0)]
        corners = [(-1, -1), (-1, 1)]
        knight_moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2),
                        (2, -1), (2, 1)]
        bad_configs = set([
            0, 1 << 0, 1 << 1, 1 << 2, 1 << 3, (1 << 0) | (1 << 3),
            (1 << 1) | (1 << 2)
        ])

        while True:
            to_fill = {}
            for x, y in map_dict.iterkeys():
                for x_offset, y_offset in neighbours:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) in map_dict:
                        continue
                    # (x2, y2) is now a point just off the island

                    neighbours_dirs = 0
                    for i in range(len(neighbours)):
                        x3 = x2 + neighbours[i][0]
                        y3 = y2 + neighbours[i][1]
                        if (x3, y3) not in map_dict:
                            neighbours_dirs |= (1 << i)
                    if neighbours_dirs in bad_configs:
                        # part of a straight 1 tile gulf
                        to_fill[(x2, y2)] = True
                    else:
                        for x_offset, y_offset in corners:
                            x3 = x2 + x_offset
                            y3 = y2 + y_offset
                            x4 = x2 - x_offset
                            y4 = y2 - y_offset
                            if (x3, y3) in map_dict and (x4, y4) in map_dict:
                                # part of a diagonal 1 tile gulf
                                to_fill[(x2, y2)] = True
                                break

                # block 1 tile straits
                for x_offset, y_offset in knight_moves:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) not in map_dict:
                        continue
                    if abs(x_offset) == 1:
                        y2 = y + y_offset / 2
                        if (x2, y2) in map_dict or (x, y2) in map_dict:
                            continue
                    else:
                        x2 = x + x_offset / 2
                        if (x2, y2) in map_dict or (x2, y) in map_dict:
                            continue
                    to_fill[(x2, y2)] = True

            if to_fill:
                for x, y in to_fill.iterkeys():
                    map_dict[(x, y)] = tile
                    map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
            else:
                break

    # possible movement directions
    all_moves = {
        'sw': (-1, -1),
        'w': (-1, 0),
        'nw': (-1, 1),
        's': (0, -1),
        'n': (0, 1),
        'se': (1, -1),
        'e': (1, 0),
        'ne': (1, 1)
    }

    def get_island_outline():
        """
		@return: the points just off the island as a dict
		"""
        result = {}
        for x, y in map_dict.iterkeys():
            for offset_x, offset_y in all_moves.itervalues():
                coords = (x + offset_x, y + offset_y)
                if coords not in map_dict:
                    result[coords] = True
        return result

    # add grass to sand tiles
    fill_tiny_spaces(GROUND.DEFAULT_LAND)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.SAND_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.SAND_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.SAND_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.SAND_NORTH
        # sandy corner
        elif filled == ['se']:
            tile = GROUND.SAND_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.SAND_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.SAND_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.SAND_NORTHEAST1
        # grassy corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.SAND_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.SAND_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.SAND_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.SAND_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    for coords, type in outline.iteritems():
        map_dict[coords] = type

    # add sand to shallow water tiles
    fill_tiny_spaces(GROUND.SAND)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.COAST_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.COAST_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.COAST_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.COAST_NORTH
        # mostly wet corner
        elif filled == ['se']:
            tile = GROUND.COAST_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.COAST_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.COAST_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.COAST_NORTHEAST1
        # mostly dry corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.COAST_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.COAST_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.COAST_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.COAST_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    for coords, type in outline.iteritems():
        map_dict[coords] = type

    # add shallow water to deep water tiles
    fill_tiny_spaces(GROUND.SHALLOW_WATER)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.DEEP_WATER_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.DEEP_WATER_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.DEEP_WATER_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.DEEP_WATER_NORTH
        # mostly deep corner
        elif filled == ['se']:
            tile = GROUND.DEEP_WATER_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.DEEP_WATER_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.DEEP_WATER_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.DEEP_WATER_NORTHEAST1
        # mostly shallow corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    map_db("COMMIT")
    return map_db
def create_random_island(id_string):
	"""Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	The coordinates of tiles will be 0 <= x < width and 0 <= y < height
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
	match_obj = re.match(_random_island_id_regexp, id_string)
	assert match_obj
	creation_method, width, height, seed = [ long(i) for i in match_obj.groups() ]
	assert creation_method == 2, 'The only supported island creation method is 2.'

	rand = random.Random(seed)
	map_set = set()

	# place this number of shapes
	for i in xrange(15 + width * height / 45):
		# place shape determined by shape_id on (x, y)
		add = True
		shape_id = rand.randint(2, 8)
		rect_chance = 29
		if rand.randint(0, 4) == 0:
			rect_chance = 13
			add = False

		shape = None
		if rand.randint(1, rect_chance) == 1:
			# use a rect
			if add:
				x = rand.randint(8, width - 7)
				y = rand.randint(8, height - 7)
			else:
				x = rand.randint(0, width)
				y = rand.randint(0, height)
			shape = Rect.init_from_topleft_and_size(x - 5, y - 5, rand.randint(2, 8), rand.randint(2, 8))
		else:
			# use a circle such that the radius is determined by shape_id
			radius = shape_id
			if not add and rand.randint(0, 6) < 5:
				x = rand.randint(-radius * 3 / 2, width + radius * 3 / 2)
				y = rand.randint(-radius * 3 / 2, height + radius * 3 / 2)
				shape = Circle(Point(x, y), shape_id)
			elif width - radius - 4 >= radius + 3 and height - radius - 4 >= radius + 3:
				x = rand.randint(radius + 3, width - radius - 4)
				y = rand.randint(radius + 3, height - radius - 4)
				shape = Circle(Point(x, y), shape_id)

		if shape:
			for shape_coord in shape.tuple_iter():
				if add:
					map_set.add(shape_coord)
				elif shape_coord in map_set:
					map_set.discard(shape_coord)

	# write values to db
	map_db = DbReader(":memory:")
	map_db("CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL, action_id TEXT NOT NULL, rotation INTEGER NOT NULL)")
	map_db("CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)")
	map_db("BEGIN TRANSACTION")

	# add grass tiles
	for x, y in map_set:
		map_db("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", x, y, *GROUND.DEFAULT_LAND)

	def fill_tiny_spaces(tile):
		"""Fills 1 tile gulfs and straits with the specified tile
		@param tile: ground tile to fill with
		"""

		all_neighbours = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
		neighbours = [(-1, 0), (0, -1), (0, 1), (1, 0)]
		corners = [(-1, -1), (-1, 1)]
		knight_moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)]
		bad_configs = set([0, 1 << 0, 1 << 1, 1 << 2, 1 << 3, (1 << 0) | (1 << 3), (1 << 1) | (1 << 2)])

		edge_set = copy.copy(map_set)
		reduce_edge_set = True

		while True:
			to_fill = set()
			to_ignore = set()
			for x, y in edge_set:
				# ignore the tiles with no empty neighbours
				if reduce_edge_set:
					is_edge = False
					for x_offset, y_offset in all_neighbours:
						if (x + x_offset, y + y_offset) not in map_set:
							is_edge = True
							break
					if not is_edge:
						to_ignore.add((x, y))
						continue

				for x_offset, y_offset in neighbours:
					x2 = x + x_offset
					y2 = y + y_offset
					if (x2, y2) in map_set:
						continue
					# (x2, y2) is now a point just off the island

					neighbours_dirs = 0
					for i in xrange(len(neighbours)):
						x3 = x2 + neighbours[i][0]
						y3 = y2 + neighbours[i][1]
						if (x3, y3) not in map_set:
							neighbours_dirs |= (1 << i)
					if neighbours_dirs in bad_configs:
						# part of a straight 1 tile gulf
						to_fill.add((x2, y2))
					else:
						for x_offset, y_offset in corners:
							x3 = x2 + x_offset
							y3 = y2 + y_offset
							x4 = x2 - x_offset
							y4 = y2 - y_offset
							if (x3, y3) in map_set and (x4, y4) in map_set:
								# part of a diagonal 1 tile gulf
								to_fill.add((x2, y2))
								break

				# block 1 tile straits
				for x_offset, y_offset in knight_moves:
					x2 = x + x_offset
					y2 = y + y_offset
					if (x2, y2) not in map_set:
						continue
					if abs(x_offset) == 1:
						y2 = y + y_offset / 2
						if (x2, y2) in map_set or (x, y2) in map_set:
							continue
					else:
						x2 = x + x_offset / 2
						if (x2, y2) in map_set or (x2, y) in map_set:
							continue
					to_fill.add((x2, y2))

				# block diagonal 1 tile straits
				for x_offset, y_offset in corners:
					x2 = x + x_offset
					y2 = y + y_offset
					x3 = x + 2 * x_offset
					y3 = y + 2 * y_offset
					if (x2, y2) not in map_set and (x3, y3) in map_set:
						to_fill.add((x2, y2))
					elif (x2, y2) in map_set and (x2, y) not in map_set and (x, y2) not in map_set:
						to_fill.add((x2, y))

			if to_fill:
				for x, y in to_fill:
					map_set.add((x, y))
					map_db("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", x, y, *tile)

				old_size = len(edge_set)
				edge_set = edge_set.difference(to_ignore).union(to_fill)
				reduce_edge_set = old_size - len(edge_set) > 50
			else:
				break

	# possible movement directions
	all_moves = {
		'sw' : (-1, -1),
		'w'  : (-1, 0),
		'nw' : (-1, 1),
		's'  : (0, -1),
		'n'  : (0, 1),
		'se' : (1, -1),
		'e'  : (1, 0),
		'ne' : (1, 1)
		}

	def get_island_outline():
		"""
		@return: the points just off the island as a dict
		"""
		result = set()
		for x, y in map_set:
			for offset_x, offset_y in all_moves.itervalues():
				coords = (x + offset_x, y + offset_y)
				if coords not in map_set:
					result.add(coords)
		return result

	# add grass to sand tiles
	fill_tiny_spaces(GROUND.DEFAULT_LAND)
	outline = get_island_outline()
	for x, y in outline:
		filled = []
		for dir in sorted(all_moves):
			coords = (x + all_moves[dir][1], y + all_moves[dir][0])
			if coords in map_set:
				filled.append(dir)

		tile = None
		# straight coast or 1 tile U-shaped gulfs
		if filled == ['s', 'se', 'sw'] or filled == ['s']:
			tile = GROUND.SAND_NORTH
		elif filled == ['e', 'ne', 'se'] or filled == ['e']:
			tile = GROUND.SAND_WEST
		elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
			tile = GROUND.SAND_SOUTH
		elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
			tile = GROUND.SAND_EAST
		# slight turn (looks best with straight coast)
		elif filled == ['e', 'se'] or filled == ['e', 'ne']:
			tile = GROUND.SAND_WEST
		elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
			tile = GROUND.SAND_SOUTH
		elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
			tile = GROUND.SAND_EAST
		elif filled == ['s', 'sw'] or filled == ['s', 'se']:
			tile = GROUND.SAND_NORTH
		# sandy corner
		elif filled == ['se']:
			tile = GROUND.SAND_NORTHWEST1
		elif filled == ['ne']:
			tile = GROUND.SAND_SOUTHWEST1
		elif filled == ['nw']:
			tile = GROUND.SAND_SOUTHEAST1
		elif filled == ['sw']:
			tile = GROUND.SAND_NORTHEAST1
		# grassy corner
		elif 3 <= len(filled) <= 5:
			coast_set = set(filled)
			if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
				tile = GROUND.SAND_NORTHEAST3
			elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
				tile = GROUND.SAND_NORTHWEST3
			elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
				tile = GROUND.SAND_SOUTHWEST3
			elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
				tile = GROUND.SAND_SOUTHEAST3

		assert tile
		map_db("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", x, y, *tile)
	map_set = map_set.union(outline)

	# add sand to shallow water tiles
	fill_tiny_spaces(GROUND.SAND)
	outline = get_island_outline()
	for x, y in outline:
		filled = []
		for dir in sorted(all_moves):
			coords = (x + all_moves[dir][1], y + all_moves[dir][0])
			if coords in map_set:
				filled.append(dir)

		tile = None
		# straight coast or 1 tile U-shaped gulfs
		if filled == ['s', 'se', 'sw'] or filled == ['s']:
			tile = GROUND.COAST_NORTH
		elif filled == ['e', 'ne', 'se'] or filled == ['e']:
			tile = GROUND.COAST_WEST
		elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
			tile = GROUND.COAST_SOUTH
		elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
			tile = GROUND.COAST_EAST
		# slight turn (looks best with straight coast)
		elif filled == ['e', 'se'] or filled == ['e', 'ne']:
			tile = GROUND.COAST_WEST
		elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
			tile = GROUND.COAST_SOUTH
		elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
			tile = GROUND.COAST_EAST
		elif filled == ['s', 'sw'] or filled == ['s', 'se']:
			tile = GROUND.COAST_NORTH
		# mostly wet corner
		elif filled == ['se']:
			tile = GROUND.COAST_NORTHWEST1
		elif filled == ['ne']:
			tile = GROUND.COAST_SOUTHWEST1
		elif filled == ['nw']:
			tile = GROUND.COAST_SOUTHEAST1
		elif filled == ['sw']:
			tile = GROUND.COAST_NORTHEAST1
		# mostly dry corner
		elif 3 <= len(filled) <= 5:
			coast_set = set(filled)
			if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
				tile = GROUND.COAST_NORTHEAST3
			elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
				tile = GROUND.COAST_NORTHWEST3
			elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
				tile = GROUND.COAST_SOUTHWEST3
			elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
				tile = GROUND.COAST_SOUTHEAST3

		assert tile
		map_db("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", x, y, *tile)
	map_set = map_set.union(outline)

	# add shallow water to deep water tiles
	fill_tiny_spaces(GROUND.SHALLOW_WATER)
	outline = get_island_outline()
	for x, y in outline:
		filled = []
		for dir in sorted(all_moves):
			coords = (x + all_moves[dir][1], y + all_moves[dir][0])
			if coords in map_set:
				filled.append(dir)

		tile = None
		# straight coast or 1 tile U-shaped gulfs
		if filled == ['s', 'se', 'sw'] or filled == ['s']:
			tile = GROUND.DEEP_WATER_NORTH
		elif filled == ['e', 'ne', 'se'] or filled == ['e']:
			tile = GROUND.DEEP_WATER_WEST
		elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
			tile = GROUND.DEEP_WATER_SOUTH
		elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
			tile = GROUND.DEEP_WATER_EAST
		# slight turn (looks best with straight coast)
		elif filled == ['e', 'se'] or filled == ['e', 'ne']:
			tile = GROUND.DEEP_WATER_WEST
		elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
			tile = GROUND.DEEP_WATER_SOUTH
		elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
			tile = GROUND.DEEP_WATER_EAST
		elif filled == ['s', 'sw'] or filled == ['s', 'se']:
			tile = GROUND.DEEP_WATER_NORTH
		# mostly deep corner
		elif filled == ['se']:
			tile = GROUND.DEEP_WATER_NORTHWEST1
		elif filled == ['ne']:
			tile = GROUND.DEEP_WATER_SOUTHWEST1
		elif filled == ['nw']:
			tile = GROUND.DEEP_WATER_SOUTHEAST1
		elif filled == ['sw']:
			tile = GROUND.DEEP_WATER_NORTHEAST1
		# mostly shallow corner
		elif 3 <= len(filled) <= 5:
			coast_set = set(filled)
			if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
				tile = GROUND.DEEP_WATER_NORTHEAST3
			elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
				tile = GROUND.DEEP_WATER_NORTHWEST3
			elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
				tile = GROUND.DEEP_WATER_SOUTHWEST3
			elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
				tile = GROUND.DEEP_WATER_SOUTHEAST3

		assert tile
		map_db("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", x, y, *tile)

	map_db("COMMIT")
	return map_db
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_dict = {}

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island

    # place this number of shapes
    for i in xrange(int(float(width + height) / 2 * 1.5)):
        x = rand.randint(4, width - 4)
        y = rand.randint(4, height - 4)

        # place shape determined by shape_id on (x, y)
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)

        if rand.randint(1, 4) == 1:
            # use a rect
            if creation_method == 0:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 3, y - 3, 5, 5).tuple_iter():
                    map_dict[shape_coord] = 1
            elif creation_method == 1:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 5, y - 5, 8, 8).tuple_iter():
                    map_dict[shape_coord] = 1

        else:
            # use a circle, where radius is determined by shape_id
            for shape_coord in Circle(Point(x, y), shape_id).tuple_iter():
                map_dict[shape_coord] = 1

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # assign these characters, if a coastline is found in this offset
    offset_coastline = {'a': (0, -1), 'b': (1, 0), 'c': (0, 1), 'd': (-1, 0)}

    for x, y in map_dict.iterkeys():
        # add a coastline tile for coastline, or default land else
        coastline = ""
        for offset_char in sorted(offset_coastline):
            if (x + offset_coastline[offset_char][0],
                    y + offset_coastline[offset_char][1]) not in map_dict:
                coastline += offset_char

        if coastline:
            # TODO: use coastline tile depending on coastline
            map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, 49)
        else:
            map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y,
                   GROUND.DEFAULT_LAND)
    map_db("COMMIT")
    return map_db