Example #1
0
def cell_auto(matrix: list, alivelimit: int = 4, deadlimit: int = 5) -> list:
    w, h = dimensions(matrix)
    copy = deepcopy(matrix)
    for i in range(w):
        for j in range(h):
            cell = matrix[j][i]
            neighbors = 0
            alive = 0
            for ii, jj in squares(exclude_center=True):
                # check if neighbor is within bounds
                try:
                    c = matrix[j + jj][i + ii]
                except:
                    pass
                else:
                    alive += 1
                    if c == '#':
                        neighbors += 1
            if alive < 6:
                continue
            if cell == '#':
                if neighbors < deadlimit:
                    copy[j][i] = '.'
            elif cell == '.':
                if neighbors > alivelimit:
                    copy[j][i] = '#'
    return copy
Example #2
0
def open_door(engine, entity):
    """TODO: render log message when opening a door of multiple doors"""
    position = engine.positions.find(entity)
    turn_over = False
    # get all coordinates surrounding current entity position
    coordinates = [
        (position.x + x, position.y + y)
            for x, y in squares(exclude_center=True)
    ]
    g = join(engine.openables, engine.positions, engine.renders, engine.infos)
    doors = {}
    # compare coordinates against entities that can be opened that have a
    # a position x, y value in the coordinates list.
    for openable_id, (openable, coordinate, render, info) in g:
        valid_coordinate = (coordinate.x, coordinate.y) in coordinates
        if valid_coordinate and not openable.opened:
            x = coordinate.x - position.x
            y = coordinate.y - position.y
            doors[(x, y)] = (openable_id, openable, coordinate, render, info)
    door_to_open = None
    if not doors:
        engine.logger.add(f"No closed doors to open.")
    elif len(doors) == 1:
        door_to_open, = doors.values()
    else:
        engine.logger.add(f"Which door to open?")
        engine.screen.render()
        engine.input_system.process(
            valid_keypresses=set(keypress_to_direction).union(('escape',))
        )
        keypress = engine.get_keypress()
        movement = Movement.keypress_to_direction(keypress)
        # valid direction keypress but not valid door direction
        door = doors.get((movement.x, movement.y), None)
        if not door:
            engine.logger.add(
                f"You cancel opening a door. Direction invalid error."
            )
        else:
            door_to_open = door
    if door_to_open:
        door, openable, position, render, info = door_to_open
        openable.opened = True
        position.blocks = False
        # replace info
        engine.infos.add(door, engine.infos.shared['opened door'])
        # replace the render
        engine.renders.add(
            door,
            random.choice(engine.renders.shared['opened door'])
        )
        engine.logger.add(f"You open the door.")
        turn_over = True
    return turn_over
Example #3
0
def ai_system(engine):
    c = engine.current_turns.find(engine.entity)
    ai = engine.ais.find(engine.entity)
    if not c.finished and ai:
        room = engine.tilemaps.find(engine.room)
        position = engine.positions.find(engine.entity)
        spaces = {(x, y)
                  for y in range(1, room.height - 1)
                  for x in range(1, room.width - 1)}
        moveable = [(x, y) for x, y in squares(exclude_center=True)
                    if (position.x + x, position.y + y) in spaces]
        engine.movements.add(engine.entity, Movement.random_move(moveable))
        c.finished = True
Example #4
0
def astar_gui(tiles, start, end, paths=squares):
    """Note: This is for demo purposes only. Used only in demos/astar2.py"""
    heap = []
    path = {}
    closed = set()
    # holds score from current node to neighbor
    gs = { (start.x, start.y): 0 }
    # holds score from current node to end node
    fs = { (start.x, start.y): heuristic((start.x, start.y), (end.x, end.y)) }
    
    heappush(heap, (fs[(start.x, start.y)], (start.x, start.y)))

    while heap:
        current = heappop(heap)[1]
        closed.add(current)

        if current == (end.x, end.y):
            # found node: return reversed path
            for p in path:
                yield p, 2
            data = []
            while current in path:
                data.append(current)
                current = path[current]
            data.reverse()
            for d in data:
                yield d, 3
            return

        for i, j in squares(exclude_center=True):
            neighbor = (current[0] + i, current[1] + j)
            new_g = gs[current] + heuristic(current, neighbor)
            tile = tiles.get(neighbor, None)

            if not tile or tile in ('#', '+'):
                continue
                
            if neighbor in closed and new_g >= gs.get(neighbor, 0):
                continue

            faster = new_g < gs.get(neighbor, 0)
            unexplored = neighbor not in (i[1] for i in heap)
            if faster or unexplored:
                path[neighbor] = current
                gs[neighbor] = new_g
                fs[neighbor] = new_g + heuristic(neighbor, (end.x, end.y))
                heappush(heap, (fs[neighbor], neighbor))
    # no path is found
    for p in path:
        yield p, 2
Example #5
0
def close_door(engine, entity):
    """TODO: cannot close door when unit is standing on the cell"""
    position = engine.positions.find(entity)
    turn_over = False
    # get all coordinates surrounding current entity position
    coordinates = [
        (position.x + x, position.y + y)
            for x, y in squares(exclude_center=True)
    ]
    g = join(engine.openables, engine.positions, engine.renders)
    doors = {}
    # compare coordinates against entities that can be closed that have a
    # a position x, y value in the coordinates list.
    for closeable_id, (closeable, coordinate, render) in g:
        if (coordinate.x, coordinate.y) in coordinates and closeable.opened:
            x = coordinate.x - position.x
            y = coordinate.y - position.y
            doors[(x, y)] = (closeable_id, closeable, coordinate, render)
    door_to_close = None
    if not doors:
        engine.logger.add(f"No opened door to close.")
    elif len(doors) == 1:
        door_to_close, = doors.values()
    else:
        engine.logger.add(f"Which door to close?")
        engine.screen.render()
        engine.input_system.process(
            keypresses=set(keypress_to_direction.keys()).union(('escape',))
        )
        keypress = engine.get_keypress()
        movement = Movement.keypress_to_direction(keypress)
        # valid direction keypress but not valid door direction
        door = doors.get((movement.x, movement.y), None)
        if not door:
            engine.logger.add(f"You cancel closing a door.")
        else:
            door_to_close = door
    if door_to_close:
        door, closeable, position, render = door_to_close
        closeable.opened = False
        position.blocks = True
        engine.renders.add(
            door, 
            random.choice(engine.renders.shared['closed wooden door'])
        )
        engine.logger.add(f"You close the door.")
        turn_over = True
    return turn_over
Example #6
0
def add_doors(cave, rooms):
    # create doors based on specific rules
    # _ | 0 1 2
    # --+-------
    # 0 | 0 1 2
    # 1 | 3 4 5
    # 2 | 6 7 8
    # if the tile @ 5 has neighbors only at 2/8 or 4/6 that are both walls
    # and the 5 tile is a floor then the 5 tile can transform into a door
    transform = set()
    width, height = dimensions(cave)
    for r, room in enumerate(rooms):
        # chance to a closed room
        if not random.randint(0, 1):
            continue
        # x, y = center(room)
        # cave[y][x] = r+1
        for x, y in wall_coordinates(room):
            if cave[y][x] != '.':
                continue
            subset = empty_matrix(3, 3, ' ')
            # check both cases to generate a door
            for i, j in squares(exclude_center=True):
                if x + i > width - 1:
                    continue
                if y + j > height - 1:
                    continue
                subset[j + 1][i + 1] = cave[y + j][x + i]
            added = 0
            # 1/7 are walls, 3/5 are floors
            if (subset[0][1] == '#' and subset[2][1] == '#'
                    and (x - 1, y) not in transform
                    and (x + 1, y) not in transform):
                transform.add((x, y))
                added = 1
            # 3/5 are walls, 1/7 are floors
            elif (subset[1][0] == '#' and subset[1][2] == '#'
                  and (x, y - 1) not in transform
                  and (x, y + 1) not in transform):
                transform.add((x, y))
                added = 2
            # print(string(subset), f'{r+1} {cave[y][x]} {added}\n')
    for x, y in transform:
        cave[y][x] = '+'
Example #7
0
def astar(tiles, start, end):
    heap = []
    path = {}
    closed = set()
    # holds score from current node to neighbor
    gs = {(start.x, start.y): 0}
    # holds score from current node to end node
    fs = {(start.x, start.y): octile((start.x, start.y), (end.x, end.y))}

    heappush(heap, (fs[(start.x, start.y)], (start.x, start.y)))

    while heap:
        current = heappop(heap)[1]
        # found node: return reversed path
        if current == (end.x, end.y):
            data = []
            while current in path:
                data.append(current)
                current = path[current]
            data.reverse()
            return data

        closed.add(current)
        for i, j in squares(exclude_center=True):
            neighbor = (current[0] + i, current[1] + j)
            new_g = gs[current] + octile(current, neighbor)
            tile = tiles.get(neighbor, None)

            if not tile or tile in ('#', '+'):
                continue

            if neighbor in closed and new_g >= gs.get(neighbor, 0):
                continue

            faster = new_g < gs.get(neighbor, 0)
            unexplored = neighbor not in [i[1] for i in heap]
            if faster or unexplored:
                path[neighbor] = current
                gs[neighbor] = new_g
                fs[neighbor] = new_g + octile(neighbor, (end.x, end.y))
                heappush(heap, (fs[neighbor], neighbor))
    return []
Example #8
0
def test_squares_exclusive():
    assert len(list(squares(exclude_center=True))) == 8
Example #9
0
def test_squares_inclusive():
    assert len(list(squares())) == 9
Example #10
0
 def random_move(cls, possible_spaces=None):
     if not possible_spaces:
         possible_spaces = [(x, y) for x, y in squares()]
     index = random.randint(0, len(possible_spaces) - 1)
     x, y = possible_spaces[index]
     return cls(x, y)