Example #1
0
def draw(canvas: curses.window):
    canvas.border()
    canvas.nodelay(True)

    # https://docs.python.org/3/library/curses.html#curses.window.getmaxyx
    window_height, window_width = canvas.getmaxyx()
    # rows and columns greater by one then real window size
    max_y, max_x = window_height - 1, window_width - 1

    curses.curs_set(False)

    # Reducing max dimensions by 2 allows to avoid "curses.error"
    stars_max_y = window_height - 2
    stars_max_x = window_width - 2
    coroutines = [
        blink(
            canvas,
            random.randint(1, stars_max_y),  # stars mustn't appear on border
            random.randint(0, stars_max_x),
            delay=random.randint(1, 20),
        ) for _ in range(random.randint(100, 200))
    ]

    coroutines.append(animate_rocket_flight(canvas, max_y, max_x))

    while coroutines:
        for coro in coroutines.copy():
            try:
                coro.send(None)
            except StopIteration:
                coroutines.remove(coro)
        canvas.refresh()
        time.sleep(TIC_TIMEOUT)
Example #2
0
def display_menu(screen: curses.window, menu_items, cur_index: int):
    """
    prints the menu to the console
    """

    # obtaining size of the screen
    sheight, swidth = screen.getmaxyx()

    welcome = "Welcome to Battleships"

    screen.addstr(1, swidth // 2 - len(welcome) // 2, '#' * len(welcome))
    screen.addstr(2, swidth // 2 - len(welcome) // 2, welcome)
    screen.addstr(3, swidth // 2 - len(welcome) // 2, '#' * len(welcome))

    # printing the menu in center of the screen
    for index, item in enumerate(menu_items):
        x = swidth // 2 - len(item) // 2
        y = sheight // 2 - len(menu_items) // 2 + index
        if index == cur_index:
            screen.attron(curses.color_pair(1))
            screen.addstr(y, x, item)
            screen.attroff(curses.color_pair(1))
        else:
            screen.addstr(y, x, item)

    screen.refresh()
Example #3
0
def curses_program(screen: curses.window):
    y, x = screen.getmaxyx()
    o = Ocean(x - 1, y - 1)
    screen.clear()
    curses.resizeterm(y, x)

    for instruct in data:
        screen.clear()
        curr_north, curr_east = c.north, c.east
        c.execute_instruction(instruct)
        new_north, new_east = c.north, c.east

        if new_north < curr_north:
            for i in range(abs(curr_north - new_north)):
                o.move_ocean_south()
                o.draw(screen)
        else:
            for i in range(abs(curr_north - new_north)):
                o.move_ocean_north()
                o.draw(screen)

        if new_east < curr_east:
            for i in range(abs(curr_east - new_east)):
                o.move_ocean_west()
                o.draw(screen)
        else:
            for i in range(abs(curr_east - new_east)):
                o.move_ocean_east()
                o.draw(screen)
Example #4
0
 def __init__(self,
              _x,
              _y,
              _window: curses.window,
              _orientation: int = 0,
              _arr: Union[None, list] = None,
              _score=4):
     """
     класс фигуры  ##
                   ##
     :param _x:
     :param _y:
     :param _window:  window_magic_creater
     :param _orientation:
     :param _arr:
     :param _score:
     """
     self.x = _x
     self.y = _y
     self.window = _window
     self.max_x = _window.getmaxyx()[1] - 2
     self.max_y = _window.getmaxyx()[0] - 2
     self.exist = True
     self.arr = _arr
     self.score = _score
     self.orientation = _orientation
Example #5
0
def draw_frame(canvas: curses.window,
               start_row: int,
               start_column: int,
               text: str,
               negative: bool = False):
    """Draw multiline text fragment on canvas. Erase text instead of drawing if negative=True is specified."""

    rows_number, columns_number = canvas.getmaxyx()

    for row, line in enumerate(text.splitlines(), round(start_row)):
        if row < 0:
            continue

        if row >= rows_number:
            break

        for column, symbol in enumerate(line, round(start_column)):
            if column < 0:
                continue

            if column >= columns_number:
                break

            if symbol == " ":
                continue

            # Check that current position it is not in a lower right corner of the window
            # Curses will raise exception in that case. Don`t ask why…
            # https://docs.python.org/3/library/curses.html#curses.window.addch
            if row == rows_number - 1 and column == columns_number - 1:
                continue

            symbol = symbol if not negative else " "
            canvas.addch(row, column, symbol)
Example #6
0
def display_stats(screen: curses.window, statistics, my: bool, game: Game):
    """
    function for printing a table displaying how many ships are alive/dead
    """
    # if the size of the longest ship is greater than 50
    # then tables with stats won't fit on the screen
    # thus, just don't print it
    if game.longest_ship_sz > 50:
        return

    sheight, swidth = screen.getmaxyx()

    title = "Your Ships" if my else "Enemy Ships"
    str_size = "Size"
    str_alive = "Alive"
    str_dead = "Dead"
    col_names = f"| {str_size} | {str_alive} | {str_dead} |"
    offset_x = 0

    # Each table is 8 blocks away from fields
    if my:
        offset_x = swidth // 2 - Field.WINDOW_WIDTH * len(Field.EMPTY) // 2 \
                   - len(str(game.map_width)) - len(col_names) - 8
    else:
        offset_x = swidth // 2 - Field.WINDOW_WIDTH * len(Field.EMPTY) // 2 \
                   + (len(Field.EMPTY) + 1) * Field.WINDOW_WIDTH + 8

    # Each table close to the middle of the fields but at least 1 block away from the top of the console
    offset_y = max(1, (Field.WINDOW_HEIGHT * 2 + 10) // 2 -
                   (len(statistics) + 3) // 2)
    longest_ship_sz = game.longest_ship_sz

    # printing table's heading
    screen.addstr(offset_y, offset_x + (len(col_names) // 2 - len(title) // 2),
                  title)
    screen.addstr(offset_y + 1, offset_x, "-" * (len(col_names)))
    screen.addstr(offset_y + 2, offset_x, col_names)

    # printing stats
    row = 3
    for i in range(len(statistics)):
        alive = str(statistics[i])
        dead = str(longest_ship_sz - (i + 1) + 1 - statistics[i])
        # cross out if there are no alive ships
        if alive == '0':
            screen.addstr(offset_y + row, offset_x,
                          "|" + "/" * (len(col_names) - 2) + "|")
        else:
            screen.addstr(
                offset_y + row, offset_x, "| " + str(i + 1) + " " *
                (len(str_size) + 1 - len(str(i + 1))) + '| ' + alive + " " *
                (len(str_alive) + 1 - len(alive)) + '| ' + dead + " " *
                (len(str_dead) + 1 - len(dead)) + "|")
        row += 1

    screen.addstr(offset_y + row, offset_x, "-" * (len(col_names)))
Example #7
0
def show_sprite(scr: c.window, sprite: list, erase=True):
    if erase:
        scr.erase()
    scr_y, scr_x = scr.getmaxyx()
    begin_y = scr_y // 2 - len(sprite) // 2
    begin_x = scr_x // 2 - len(sprite[0]) // 2

    for i, s in enumerate(sprite):
        scr.addstr(begin_y + i, begin_x, s)
    scr.refresh()
Example #8
0
def print_to_center(screen: curses.window, messages) -> None:
    """
    function for printing messages to the center of the screen
    :param screen:
    :param messages: list-like iterable element
    """

    sheight, swidth = screen.getmaxyx()

    for index, message in enumerate(messages):
        screen.addstr(sheight // 2 + index, swidth // 2 - len(message) // 2,
                      message)
Example #9
0
def main(screen: curses.window, height, width):
    game: Optional[Game] = None
    curses.curs_set(0)
    while True:
        display_string_builder: list[str, ...] = list()
        display_string_builder.append('###########################')
        display_string_builder.append('#  WELCOME TO BATTLESHIP  #')
        display_string_builder.append('###########################')
        display_string_builder.append('')

        if game and game.winner:
            display_string_builder.append(
                f'The winner of the last game is {game.winner}!')
            display_string_builder.append('')

        display_string_builder.append('Press n to start new game.')
        display_string_builder.append('Press l to load the game (if exists).')
        display_string_builder.append('Press q to quit the game.')

        screen.clear()
        check_text_size(display_string_builder, *screen.getmaxyx())
        display_string = '\n'.join(display_string_builder)
        screen.addstr(0, 0, display_string)

        input_character = screen.getch()

        if input_character == ord('q'):
            return

        if input_character in (ord('n'), ord('l')):
            if input_character == ord('l'):
                try:
                    with open(SAVE_FILE_NAME, 'rb') as file:
                        game = pickle.load(file)
                except OSError:
                    continue
            else:
                first_player = HumanPlayer('You')
                second_player = RandomPlayer('Robot')
                game = Game(first_player=first_player,
                            second_player=second_player,
                            board_size=(height, width))
            try:
                game.play(screen)
            except QuitSignal as qs:
                if qs.signal_type == QuitSignal.BACK_TO_MAIN_MENU:
                    continue
                if qs.signal_type == QuitSignal.QUIT:
                    return
                if qs.signal_type == QuitSignal.QUIT_AND_SAVE:
                    with open(SAVE_FILE_NAME, 'wb') as file:
                        pickle.dump(game, file, pickle.HIGHEST_PROTOCOL)
                        return
Example #10
0
def display_game(screen: curses.window, cur_player: Player, game: Game):
    """
    function for printing game on the console
    """
    # obtain coordinates for displaying fields
    sheight, swidth = screen.getmaxyx()
    my_coords, enemy_coords = game.display_field(sheight=sheight,
                                                 swidth=swidth)

    # print fields and stats on the console
    screen.clear()
    display_field(screen, my_coords, cur_player, True, game=game)
    display_field(screen, enemy_coords, cur_player, False, game=game)
    stats = game.num_alive_ships()
    display_stats(screen=screen, statistics=stats[0], my=True, game=game)
    display_stats(screen=screen, statistics=stats[1], my=False, game=game)
Example #11
0
def run_game(scr: curses.window):
    curses.curs_set(0)
    scr.nodelay(True)
    game_state = ""
    status_w: int = 25
    maxy = scr.getmaxyx()[0] - 1
    maxx = scr.getmaxyx()[1]

    midy = int(maxy / 2)
    midx = int(maxx / 2)
    snake: list = []
    for i in range(SNAKE_LEN):
        snake.append((midy, status_w + midx + i))
    direction = WEST
    apples: list = []
    score = 0
    while True:
        scr.erase()
        draw_statusbar(scr, (maxy - 1, maxx), status_w, score)
        draw_snek(scr, snake, direction)
        draw_apples(scr, apples)
        # ++ Tick ++
        key = scr.getch()
        direction, game_state = process_key(key, direction)
        snake = move_snake(snake, direction)
        snake = portals(snake, direction, status_w + 2, (maxy - 1, maxx))
        snake, apples, nscore = eat_apples(snake, apples)
        apples = create_apples(snake, apples, MAX_APPLES - len(apples),
                               status_w, (maxy, maxx))
        score += nscore
        if game_state != "":
            return game_state, 0
        # -- Tick --
        scr.refresh()
        if check_loss(snake):
            curses.napms(1000)
            return "end", score
        curses.napms(100)
Example #12
0
def main(stdscr: curses.window) -> None:
    log.debug('Program starting.')

    command_args = get_args()
    screen_height, screen_width = stdscr.getmaxyx()
    config = configure(screen_height, screen_width, command_args)

    curses.curs_set(0)
    init_color_pairs()

    kb_pad = Pad(1, 1)
    map_pad = Pad(config.map_pad_h, config.map_pad_w)
    actor_pad = Pad(1, 1 + (1 if config.square_tiles else 0))
    status_bar_pad = Pad(1, config.status_bar_width)

    map = MapController(map_pad, config)
    actor = ActorController(actor_pad, config)
    status_bar = StatusBarController(status_bar_pad, config)

    pad_controllers = [map, actor, status_bar]

    runner = ApplicationRunner(kb_pad, pad_controllers, config)
    runner.run()
Example #13
0
def main(scr: curses.window):
    mode = "movement"
    for n, pair in enumerate(colors):
        curses.init_pair(n + 1, *pair)

    y, x = 0, 0
    while True:
        # maxy/x
        maxy, maxx = [n - 1 for n in scr.getmaxyx()]
        maxy -= 1

        # output mode
        scr.move(maxy + 1, 1)
        scr.clrtobot()
        scr.addstr(maxy + 1, 1, mode)

        # move cursor to proper position
        scr.move(y, x)

        # get user input
        key = scr.getch()
        # try:
        y, x, scr, mode = modes[mode](key, mode, y, x, maxy, maxx, scr)
Example #14
0
    def _main(stdscr: curses.window):
        maxy, maxx = 0, 0

        examples = []
        count = 1
        while 1:
            # Prompt
            maxy, maxx = stdscr.getmaxyx()
            stdscr.clear()

            stdscr.addstr(
                0, 0, "Enter example: (hit Ctrl-G to execute, Ctrl-C to exit)",
                curses.A_BOLD)
            editwin = curses.newwin(5, maxx - 4, 2, 2)
            rectangle(stdscr, 1, 1, 1 + 5 + 1, maxx - 2)

            # Printing is part of the prompt
            cur = 8

            def putstr(str, x=0, attr=0):
                nonlocal cur
                # This is how we handle going off the bottom of the scren lol
                if cur < maxy:
                    stdscr.addstr(cur, x, str, attr)
                    cur += (len(str.split("\n")) or 1)

            for ex, buff, vals, err in reversed(examples):
                putstr(f"Example {ex}:", attr=curses.A_BOLD)

                for l in buff.split("\n"):
                    putstr(f"    | {l}")

                putstr("")

                if err:
                    err = str(err)
                    err = err.split("\n")
                    putstr("  Error:")
                    for l in err:
                        putstr(f"    {l}", attr=curses.COLOR_YELLOW)

                elif vals:
                    putstr("  Value:")
                    for x, t in zip(range(1, 1 << 64), vals):
                        putstr(f" {x:>3}) " + repr(t))

                putstr("")

            stdscr.refresh()

            # Readf rom the user
            box = Textbox(editwin)
            try:
                box.edit()
            except KeyboardInterrupt:
                break

            buff = box.gather().strip()
            if not buff:
                continue

            vals, err = handle(buff, count)

            examples.append((count, buff, vals, err))

            count += 1
            stdscr.refresh()
Example #15
0
def main(scr: curses.window):
    # Remove blinking cursor
    curses.curs_set(0)

    # Get screen's height and width & check if the screen is big enough
    sh, sw = scr.getmaxyx()
    if sh < SCR_H + 2 or sw < SCR_W + 2: show_msg(scr, sh, sw, MSG_SCR_SMALL)

    # Get args
    mode, ip, port, plname = get_args(scr, sh, sw)

    # Start socket for host/join mode
    skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if mode == 'host':
        try:
            skt.bind((ip, port))
            skt.listen(1)
        except:
            show_msg(scr, sh, sw, MSG_CANT_HOST)
    else:
        try:
            skt.connect((ip, port))
        except:
            show_msg(scr, sh, sw, MSG_CANT_JOIN)

    # Setup keys
    up_key = set((curses.KEY_UP, ord('k'), ord('K'), ord('w'), ord('W')))
    down_key = set((curses.KEY_DOWN, ord('j'), ord('J'), ord('s'), ord('S')))
    quit_key = set((ord('q'), ord('Q')))
    keys = {'up_key': up_key, 'down_key': down_key, 'quit_key': quit_key}

    # Activate nodelay (so getch won't interrupt the execution)
    scr.nodelay(1)
    scr.timeout(33)

    # Create arena
    arena = Arena(0, 1, SCR_W, SCR_H)

    # Create players
    player1 = Player('left', arena)
    player2 = Player('right', arena)

    # Create the ball
    ball = Ball(arena.bound_x // 2, arena.bound_y // 2, choice((-1, 1)),
                choice((-1, 0, 1)))

    # Connection accepted
    accepted = False

    # Waiting connection message
    scr.addstr(sh // 2, sw // 2 - len(MSG_WAITING) // 2, MSG_WAITING)
    scr.refresh()
    scr.addstr(sh // 2, 0, " " * sw)

    # Draw the arena
    arena.draw(scr)

    # Game loop
    while True:
        # Start networking
        if mode == 'host':
            if not accepted:
                # Accept client
                try:
                    clskt, claddr = skt.accept()
                except:
                    sys.exit()
                # Write host name on the screen and send it
                scr.addstr(0, 0, plname)
                clskt.send(plname.encode().ljust(16))
                # Receive client name and add to screen
                try:
                    clname = clskt.recv(16).strip().decode()[:16]
                except:
                    show_msg(scr, 0, SCR_W, MSG_DISCONN)
                scr.addstr(0, SCR_W + 1 - len(clname), clname)
                # Mark client as accpeted
                accepted = True
        else:
            if not accepted:
                # Receive host name and add to screen
                try:
                    scr.addstr(0, 0, skt.recv(16).strip().decode()[:16])
                except:
                    show_msg(scr, 0, SCR_W, MSG_DISCONN)
                # Write client name on the screen and send it
                scr.addstr(0, SCR_W + 1 - len(plname), plname)
                skt.send(plname.encode().ljust(16))
                accepted = True

        # Draw the game score
        scr.addstr(0, SCR_W // 2 - 6, str(player1.score))
        scr.addstr(0, SCR_W // 2 + 6, str(player2.score))

        # Draw players
        player1.draw(scr, arena)
        player2.draw(scr, arena)

        # Draw ball (host) and check goals
        if mode == 'host':
            ball.move(player1, player2, arena)
            ball.draw(scr)

        # Get button press, perform action and send over the network
        if mode == 'host':
            action = get_action(scr, arena, player1, keys, plname == 'AI', {
                'p1': player1.y,
                'p2': player2.y,
                'ball': ball.upload()
            })
            if action == 'up' and player1.y > arena.y + 3:
                player1.move('up')
            elif action == 'down' and player1.y < arena.bound_y - 3:
                player1.move('down')
            elif action == 'quit':
                clskt.close()
                sys.exit(0)
            else:
                action = None

            # Send ball and host's action
            try:
                clskt.send(pickle.dumps((str(action), ball.upload())))
                player2_action = clskt.recv(16).strip().decode()
                if player2_action == 'up' and player2.y > arena.y + 3:
                    player2.move('up')
                elif player2_action == 'down' and player2.y < arena.bound_y - 3:
                    player2.move('down')
            except:
                show_msg(scr, 0, SCR_W, MSG_DISCONN)

        else:
            action = get_action(scr, arena, player2, keys, plname == 'AI', {
                'p1': player1.y,
                'p2': player2.y,
                'ball': ball.upload()
            })
            if action == 'up' and player2.y > arena.y + 3:
                player2.move('up')
            elif action == 'down' and player2.y < arena.bound_y - 3:
                player2.move('down')
            elif action == 'quit':
                skt.close()
                sys.exit(0)
            else:
                action = None

            # Send client's action, then get ball and host's position
            try:
                skt.send(str(action).encode().ljust(16))
                player1_action, ball_info = pickle.loads(
                    skt.recv(sys.getsizeof(('down', ball.upload())) * 3))
                if player1_action == 'up' and player1.y > arena.y + 3:
                    player1.move('up')
                elif player1_action == 'down' and player1.y < arena.bound_y - 3:
                    player1.move('down')
                ball.download(ball_info)
            except:
                show_msg(scr, 0, SCR_W, MSG_DISCONN)

            # Draw ball (join) and check goals
            ball.move(player1, player2, arena)
            ball.draw(scr)

        scr.refresh()
Example #16
0
    def collect(cls, window: curses.window) -> State:
        bounds = Bounds(*window.getmaxyx())
        player = Player(bounds=bounds)
        coins = {Coin.spawn(bounds) for __ in range(5)}

        return State(bounds=bounds, player=player, coins=coins)
Example #17
0
def _debug(scr: curses.window, *args):
    sargs = str([str(arg) for arg in args])[1:-1]
    scr.addstr(scr.getmaxyx()[0]-1, 1, sargs)
Example #18
0
def center(screen: curses.window) -> Tuple[int, int]:
    h, w = screen.getmaxyx()
    return h // 2, w // 2