コード例 #1
0
ファイル: spong.py プロジェクト: fvcalderan/spong
    def draw(self, screen: curses.window):
        """(Re)draw the ball"""
        # Erase the ball from the old position
        screen.addstr(self.old_y, self.old_x, ' ')

        # Draw the ball on the new position
        screen.addstr(self.y, self.x, 'O')
コード例 #2
0
ファイル: __main__.py プロジェクト: TooTiredOne/battleships
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()
コード例 #3
0
ファイル: danmu.py プロジェクト: NaviHX/pytools
def main(stdscr: curses.window):
    curses.echo()
    curses.nocbreak()

    width = config['size']['width']
    ol = config['size']['output_lines']
    il = config['size']['input_lines']

    real_id = str(get_real_id(room_id))
    output_win = curses.newwin(ol, width, 1, 1)
    output_win.scrollok(True)
    input_win = curses.newwin(il, width, ol + 3, 1)

    rectangle(stdscr, 0, 0, ol + 1, width + 1)
    rectangle(stdscr, ol + 2, 0, ol + 2 + il + 1, width + 1)

    if width > 'Message'.__len__():
        stdscr.addstr(ol + 1, 1, 'Message')

    if width > 'Press Enter'.__len__():
        stdscr.addstr(ol + 2 + il + 1, 1, 'Press Enter')

    stdscr.refresh()
    output_win.refresh()
    input_win.refresh()

    t = Thread(None, input_thread, args=(input_win, real_id))
    t.setDaemon(True)
    t.start()

    asyncio.run(
        start('wss://broadcastlv.chat.bilibili.com:2245/sub', real_id,
              output_win))

    t.join()
コード例 #4
0
ファイル: main.py プロジェクト: pidoorrr/aiodvmn_1
async def fire(
    canvas: curses.window,
    start_row: typing.Union[float, int],
    start_column: typing.Union[float, int],
    max_y: int,
    max_x: int,
    rows_speed: typing.Union[float, int] = -0.3,
    columns_speed: typing.Union[float, int] = 0,
):
    """Display animation of gun shot. Direction and speed can be specified."""

    row, column = start_row, start_column

    canvas.addstr(round(row), round(column), "*")
    await asyncio.sleep(0)

    canvas.addstr(round(row), round(column), "O")
    await asyncio.sleep(0)
    canvas.addstr(round(row), round(column), " ")

    row += rows_speed
    column += columns_speed

    symbol = "-" if columns_speed else "|"

    curses.beep()

    while 0 < row < max_y and 0 < column < max_x:
        canvas.addstr(round(row), round(column), symbol)
        await asyncio.sleep(0)
        canvas.addstr(round(row), round(column), " ")
        row += rows_speed
        column += columns_speed
コード例 #5
0
def input_str(y, x, scr: c.window, max_len=0, prompt=''):
    res = ''
    len_count = 0
    if prompt:
        scr.addstr(y, x, prompt)
    if max_len > 0:
        scr.addstr(y + int(bool(prompt)), x, '_' * max_len)
    while True:
        char = scr.get_wch()
        if char == '\n':
            break
        elif char in ('\b', '\x7f'):
            if len_count > 0:
                res = res[:-1]
                scr.addch(y + int(bool(prompt)), x + len_count - 1, '_')
                scr.refresh()
                len_count -= 1

        elif len(char) == 1:
            res += char
            scr.addch(y + int(bool(prompt)), x + len_count, char)
            scr.refresh()
            len_count += 1

        if 0 < max_len <= len_count:
            break

    return res
コード例 #6
0
ファイル: state.py プロジェクト: nickgashkov/jocus
    def render(self, window: curses.window) -> None:
        window.clear()

        for coin in self.coins:
            window.addstr(coin.x, coin.y, "o")

        window.addstr(self.player.x, self.player.y, "*")
コード例 #7
0
ファイル: spong.py プロジェクト: fvcalderan/spong
def show_msg(screen: curses.window, screen_height: int, screen_width: int,
             message: str):
    """Generic routine to generate an error message"""
    screen.addstr(screen_height // 2, screen_width // 2 - len(message) // 2,
                  message)
    screen.nodelay(0)
    screen.getch()
    sys.exit(0)
コード例 #8
0
ファイル: game.py プロジェクト: nickgashkov/jocus
def render_welcome_screen(window: curses.window) -> None:
    window.clear()

    window.addstr(0, 10, "jocus 0.0.1")
    window.addstr(1, 10, "collect coins and you win")
    window.addstr(3, 10, "press any key to start...")

    window.refresh()
コード例 #9
0
def sprite_init(scr: c.window, text: c.window, sprite: dict, erase=True):
    show_sprite(scr, sprite['image'], erase)
    for group in sprite['lines']:
        for i, line in enumerate(group):
            text.addstr(i, 0, line)
        text.getch()
        text.erase()
    scr.erase()
    scr.refresh()
コード例 #10
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()
コード例 #11
0
def draw_snek(scr: curses.window, snake: list, direction: tuple):
    for y, x in snake[1:]:
        scr.addstr(y, x, 's')
    if direction == NORTH:
        scr.addstr(snake[0][0], snake[0][1], '^')
    elif direction == SOUTH:
        scr.addstr(snake[0][0], snake[0][1], 'v')
    elif direction == EAST:
        scr.addstr(snake[0][0], snake[0][1], '>')
    elif direction == WEST:
        scr.addstr(snake[0][0], snake[0][1], '<')
コード例 #12
0
def threadGetKeys(win: curses.window, net: Network) -> None:
    while 1:
        try:
            key = win.getkey()
            win.addstr(" KEY = " + key)

            GlobVar.currentMovement = "Stop"
            if GlobVar.connectedToPi:
                if key == "KEY_UP":
                    GlobVar.currentMovement = "Go Forward"
                    GlobVar.last_answer = net.robotGoForward()
                elif key == "KEY_DOWN":
                    GlobVar.currentMovement = "Go Backward"
                    GlobVar.last_answer = net.robotGoBackward()
                elif key == "KEY_RIGHT":
                    GlobVar.currentMovement = "Go Right"
                    GlobVar.last_answer = net.robotGoRight()
                elif key == "KEY_LEFT":
                    GlobVar.currentMovement = "Go Left"
                    GlobVar.last_answer = net.robotGoLeft()
                elif key == " ":
                    GlobVar.currentMovement = "Stop"
                    GlobVar.last_answer = net.robotStop()
                elif key == "R" or key == 'r':
                    GlobVar.last_answer = net.robotReset()
                    GlobVar.dumberStarted = False
                elif key == "U" or key == 'u':
                    GlobVar.last_answer = net.robotStartWithoutWatchdog()
                    if GlobVar.last_answer == net.ACK:
                        GlobVar.dumberStarted = True
                    else:
                        GlobVar.dumberStarted = False
                elif key == "W" or key == 'w':
                    GlobVar.last_answer = net.robotStartWithWatchdog()
                    if GlobVar.last_answer == net.ACK:
                        GlobVar.dumberStarted = True
                    else:
                        GlobVar.dumberStarted = False
                elif key == "C" or key == 'c':
                    GlobVar.last_answer = net.robotCloseCom()
                    GlobVar.connectedToDumber = False
                    GlobVar.dumberStarted = False
                elif key == "O" or key == 'o':
                    GlobVar.last_answer = net.robotOpenCom()
                    if GlobVar.last_answer == net.ACK:
                        GlobVar.connectedToDumber = True
                    else:
                        GlobVar.connectedToDumber = False

            #if key == os.linesep or key =='q' or key == 'Q':
            #    break

        except Exception as e:
            GlobVar.exceptionmsg = "Exception received: " + str(e)
コード例 #13
0
ファイル: battleship.py プロジェクト: edyapups/battleship
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
コード例 #14
0
ファイル: __main__.py プロジェクト: TooTiredOne/battleships
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)
コード例 #15
0
ファイル: main.py プロジェクト: pidoorrr/aiodvmn_1
async def blink(
    canvas: curses.window,
    row: int,
    column: int,
    delay: int,
    symbols: typing.Sequence[str] = "+*.:",
):
    while True:
        symbol = random.choice(symbols)

        canvas.addstr(row, column, symbol, curses.A_DIM)

        for _ in range(delay):
            await asyncio.sleep(0)

        canvas.addstr(row, column, symbol)
        for _ in range(delay):
            await asyncio.sleep(0)

        canvas.addstr(row, column, symbol, curses.A_BOLD)
        for _ in range(delay):
            await asyncio.sleep(0)

        canvas.addstr(row, column, symbol)
        for _ in range(delay):
            await asyncio.sleep(0)
コード例 #16
0
ファイル: __main__.py プロジェクト: TooTiredOne/battleships
def display_field(screen: curses.window, coords, player: Player, my: bool,
                  game: Game) -> None:
    """
    function for printing fields on the console
    """
    # obtaining field
    field = player.my_field if my else player.enemy_field
    # obtaining sliding window borders
    start_left = field.border_left
    start_top = field.border_top
    iter_row = start_top
    iter_col = start_left
    for y, x, symb in coords:
        # replacing current active element with the cursor
        if iter_row == field.y_cur and iter_col == field.x_cur:
            screen.addstr(y, x, Field.CURSOR)
        else:
            screen.addstr(y, x, symb)
        # printing numbers on the top of the sliding window
        if iter_row == start_top:
            num_zeros = len(str(game.map_width)) - len(str(iter_col))
            power_of_ten = 10**len(str(game.map_width))
            screen.addstr(
                y - 1, x, "0" * num_zeros + str(iter_col) +
                " " if iter_col < power_of_ten else str(iter_col) + ' ')
        # printing numbers on the left of the sliding window
        if iter_col == start_left:
            screen.addstr(y, x - len(str(iter_row)), str(iter_row))

        iter_col += 1
        if iter_col == start_left + Field.WINDOW_WIDTH:
            iter_col = start_left
            iter_row += 1

    screen.refresh()
コード例 #17
0
ファイル: spong.py プロジェクト: fvcalderan/spong
    def draw(self, screen: curses.window, arena: Arena):
        """Draw player on the screen's defined y position"""
        # clear player's row
        for i in range(arena.y + 1, arena.bound_y - 1):
            screen.addstr(i, self.x, ' ')

        # draw the player
        screen.addstr(self.y - 1, self.x, '|')
        screen.addstr(self.y, self.x, '|')
        screen.addstr(self.y + 1, self.x, '|')
コード例 #18
0
ファイル: units.py プロジェクト: yawpitch/spacedinvaders
    def render(self, stdscr: Window) -> None:
        """
        Render the unit to screen.
        """
        # Cache the encoded lines, no sense redoing the work
        if not self._lines:
            lines = self.icon.splitlines()
            self._lines = [l.encode(CODEC) for l in lines]

        with colorize(stdscr, self.color):
            for offset_y, line in enumerate(self._lines):
                try:
                    stdscr.addstr(self.y + offset_y, self.x, line)
                except curses.error as err:
                    raise ValueError(f"y={self.y}, x={self.x}: {line}") from err

        # Unit is no longer dirty
        self._dirty = False
コード例 #19
0
ファイル: mvef.py プロジェクト: thekaigonzalez/KTerminal
def main(s: curses.window,a,c,o):
    if len(o) == 6:
        if pathlib.Path(a[0]).exists():
            s.addstr("yes\n")
        else:
            s.addstr("no.\n")
    else:
        s.addstr("Run mvef from Root to prevent problems. `sudo mvef <f>`\n")
コード例 #20
0
def start(screen: curses.window):
    while 1:

        key = screen.getch()
        screen.erase()
        h_h, h_w = center(screen)
        head_text = "Potato Messenger"
        head = (h_h // 2, h_w - len(head_text) // 2, head_text)
        click_text = "Click Here To Continue or press Enter."
        button = (h_h, h_w - len(click_text) // 2, click_text)
        box1 = screen.subwin(3,
                             len(button[2]) + 4, button[0] - 1, button[1] - 2)
        box1.box()
        screen.addstr(head[0], head[1], head[2])
        screen.addstr(button[0], button[1], button[2])
        if key == curses.KEY_ENTER or key in (10, 13):
            break
        if key == curses.KEY_MOUSE:
            _, mx, my, *_ = curses.getmouse()
            if button[1] <= mx <= button[1] + len(
                    button[2]) and my == button[0]:
                break
        screen.refresh()
コード例 #21
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)
コード例 #22
0
def show_and_calculate_analytics(
    win: curses.window,
    start_line: int,
    analyzers: List[Analyzer],
    current_lesson_log: LessonLog,
    former_lesson_logs: List[LessonLog],
) -> Tuple[List[Analytics], List[Analytics]]:
    lines = start_line
    single_lesson_analytics, whole_lesson_analytics = calculate_all_analytics(
        current_lesson_log, former_lesson_logs, analyzers)
    win.addstr(lines, 0, "Current Lesson:")
    for analytics in single_lesson_analytics:
        win.addstr(lines + 1, 0, analytics.printable_result)
        lines += len(analytics.printable_result.split("\n"))
    lines += 2
    win.addstr(lines, 0, "Whole Lesson:")
    for analytics in whole_lesson_analytics:
        win.addstr(lines + 1, 0, analytics.printable_result)
        lines += len(analytics.printable_result.split("\n"))
    return single_lesson_analytics, whole_lesson_analytics
コード例 #23
0
ファイル: client2.py プロジェクト: Nighmared/discord-bot
def curses_get_input(stdscr: curses.window, inputwin: curses.window,
                     msgqueue: Queue, status):
    to_send = ""
    next_char_x = 2
    next_char_y = 0
    inputwin.addstr(0, 0, ">>")
    inputwin.refresh()
    while status.run:
        curr_in = inputwin.getkey()
        with open("keys.log", "a") as f:
            f.write(f"got {curr_in}")
        if curr_in == "\n":
            msgqueue.put(to_send)
            to_send = ""
            inputwin.erase()
            next_char_x = next_char_y = 0
            inputwin.addstr(next_char_y, next_char_x, ">>")
            next_char_x += 2
        elif curr_in == 'KEY_BACKSPACE' or curr_in == curses.KEY_BACKSPACE or curr_in == "^?" or curr_in == "\b" or curr_in == '\x7f':
            with open("clientdebug.log", "a") as f:
                f.write(f"got key {curr_in} went into backspace case\n")
            if next_char_x == 2 and next_char_y == 0:
                continue  #nothing to delete
            if next_char_x == 0 and next_char_y > 0:  # at the start of a new line
                next_char_y -= 1
                next_char_x = INPUT_WIDTH - 1
            elif (next_char_x > 0 and next_char_y > 0) or next_char_x > 2:
                next_char_x -= 1

            inputwin.addstr(next_char_y, next_char_x, " ")
            inputwin.move(next_char_y, next_char_x)
            to_send = to_send[:-1]
        else:
            to_send += curr_in
            inputwin.addstr(next_char_y, next_char_x, curr_in)
            next_char_x += 1
            if next_char_x == INPUT_WIDTH:
                next_char_x = 0
                next_char_y += 1

        inputwin.refresh()
コード例 #24
0
def main(s: curses.window, a: list[str], c: int, o: list[bool]):
    if c == 1:
        if a[0] == "-c":
            if len(os.listdir("usr/mail")) == 0:
                s.addstr("you have no new mail")
            elif len(os.listdir("usr/mail")) > 0:
                s.addstr("you have new mail in /usr/mail")
    elif c == 3:
        if a[0] == "-u":
            if a[1] == "read":
                umailist = open('usr/mail/' + a[2] + ".ml")
                ab = umailist.readlines()
                strs = ' '.join(ab)
                s.addstr(strs)
コード例 #25
0
ファイル: end.py プロジェクト: nicey0/tui-snake
def run_end(scr: curses.window, score: int):
    curses.curs_set(0)
    message: str = f"Game over! Score: {score}"
    menu_items: list = ["Play again", "Exit"]
    game_state = ""
    cursor: int = 0
    while True:
        scr.erase()
        scr.addstr(1, 1, message, curses.A_BOLD)
        scr.addstr(2, 1, '-' * (len(message) + 5))
        for i, item in enumerate(menu_items):
            if i == cursor:
                scr.addstr(3 + i, 2, item, curses.A_REVERSE)
            else:
                scr.addstr(3 + i, 2, item)
        # ++ Tick ++
        key = scr.getch()
        cursor, game_state = process_key(key, cursor, menu_items)
        if game_state != "":
            return game_state, 0
        # -- Tick --
        scr.refresh()
コード例 #26
0
def run_mainmenu(scr: curses.window):
    curses.curs_set(0)
    title: str = "Snake"
    menu_items: list = ["Start", "Exit"]
    game_state = ""
    cursor: int = 0
    while True:
        scr.erase()
        scr.addstr(1, 1, title, curses.A_BOLD)
        scr.addstr(2, 1, '-'*(len(title)*2))
        for i, item in enumerate(menu_items):
            if i == cursor:
                scr.addstr(3+i, 2, item, curses.A_REVERSE)
            else:
                scr.addstr(3+i, 2, item)
        # ++ Tick ++
        key = scr.getch()
        cursor, game_state = process_key(key, cursor, menu_items)
        if game_state != "":
            return game_state, 0
        # -- Tick --
        scr.refresh()
コード例 #27
0
def main(s: curses.window, a, c, o):
    try:
        curses.noecho()
        s.addstr("enter password: "******"usr/beta/.private-login")
        ifdef = s.getstr().decode(encoding='utf-8')
        curses.echo()
        if ifdef == par["Info"]["PASSWORD"]:

            o.append(True)
            terminal.eval.Evaluatecommand(
                a.pop(0) + " " + ' '.join(a), "./usr/sbin", s, o)
        else:
            s.addstr("invalid password.\n")
            curses.echo()
    except Exception as we:

        s.addstr(
            "Login file not found. Please login by using the PWD utility.\n" +
            we.__str__() + "\n")
コード例 #28
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()
コード例 #29
0
ファイル: spong.py プロジェクト: fvcalderan/spong
    def draw(self, screen: curses.window):
        """Draws the arena on the screen"""
        for i in range(self.y, self.bound_y):
            screen.addstr(i, self.x, '|')
            screen.addstr(i, self.bound_x, '|')

        for i in range(self.x, self.bound_x):
            screen.addstr(self.y, i, '-')
            screen.addstr(self.bound_y, i, '-')

        screen.addstr(self.y, self.x, '+')
        screen.addstr(self.bound_y, self.x, '+')
        screen.addstr(self.y, self.bound_x, '+')
        screen.addstr(self.bound_y, self.bound_x, '+')
コード例 #30
0
ファイル: spong.py プロジェクト: fvcalderan/spong
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()