Exemplo n.º 1
0
def main():
    out = StarLog(level=1, time=datetime.datetime.now, star="* Thread-0")
    out.comment("initialising server")

    # set up a shared matchmaking pool
    pool = MatchmakingPool()

    # listen for connections incoming on PORT:
    connections = Connection.iter_listen(HOST, PORT)
    out.comment(f"listening on port {PORT}...")
    for connection, address in connections:
        # repeatedly accept a new connection, and hand off to a new thread
        out.comment("new client connected: ", address)

        out.comment("starting a new thread to handle this client...")
        handler = threading.Thread(target=servant, args=(connection, pool))
        handler.daemon = True  # so that this thread exits when main exits
        handler.start()
Exemplo n.º 2
0
def main():
    out = StarLog(level=1 + DEBUG, timefn=lambda: f"Thread-0 {datetime.now()}")
    out.comment("initialising server", depth=-1)

    # set up a shared matchmaking pool
    pool = MatchmakingPool(num_players=NUM_PLAYERS,
                           special_channels=SPECIAL_CHANNELS)

    # listen for connections incoming on PORT:
    try:
        # Host of "" allows all incoming connections on the chosen port
        connections = Connection.iter_listen(host="", port=DEFAULT_SERVER_PORT)
        out.comment(f"listening on port {DEFAULT_SERVER_PORT}...")
        for connection, address in connections:
            # repeatedly accept a new connection, and hand off to a new thread
            out.comment("new client connected: ", address)
            out.comment("starting a new thread to handle this client...")
            handler = threading.Thread(target=servant, args=(connection, pool))
            handler.daemon = True  # so that new thread exits when main exits
            handler.start()
    except KeyboardInterrupt:
        print()  # end line
        out.comment("bye!")
Exemplo n.º 3
0
def connect_and_play(player,
                     name,
                     channel,
                     host,
                     port,
                     logfilename=None,
                     out_function=None,
                     print_state=True,
                     use_debugboard=False,
                     use_colour=False,
                     use_unicode=False):
    """
    Connect to and coordinate a game with a server, return a string describing
    the result.
    """
    # Configure behaviour of this function depending on parameters:
    out = out_function if out_function else (lambda *_, **__: None)  # no-op
    if print_state:

        def display_state(players_str, game):
            out("displaying game info:")
            out(players_str, depth=1)
            out(game, depth=1)
    else:

        def display_state(players, game):
            pass

    # Set up a connection with the server
    out("connecting to battleground", depth=-1)
    out("attempting to connect to the server...")
    server = Server.from_address(host, port)
    out("connection established!")

    # Wait for some matching players
    out("looking for a game", depth=-1)
    channel_str = f"channel '{channel}'" if channel else "open channel"
    out(f"submitting game request as '{name}' in {channel_str}...")
    server.send(M.PLAY, name=name, channel=channel)
    server.recv(M.OKAY)
    out("game request submitted.")
    out(f"waiting for opponents in {channel_str}...")
    out("(press ^C to stop waiting)")
    # (wait through some OKAY-OKAY msg exchanges until a GAME message comes---
    # the server is asking if we are still here waiting, or have disconnected)
    gamemsg = server.recv(M.OKAY | M.GAME)
    while gamemsg['mtype'] is not M.GAME:
        server.send(M.OKAY)
        gamemsg = server.recv(M.OKAY | M.GAME)
    # when we get a game message, it's time to play!
    out("setting up game", depth=-1, clear=True)
    out("opponents found!")
    out("white player:", gamemsg['white'])
    out("black player:", gamemsg['black'])

    # Initialise the player
    out("initialising player", depth=-1)
    out("waiting for colour assignment...")
    initmsg = server.recv(M.INIT)
    out("playing as", initmsg['colour'], depth=1)
    out("initialising your player class...")
    player.init(initmsg['colour'])
    out("ready to play!")
    server.send(M.OKAY)

    # Set up a new game and display the initial state and players
    out("game start", depth=-1)
    players_str = format_players_str(gamemsg, player.colour)
    game = Game(logfilename=logfilename,
                debugboard=use_debugboard,
                colourboard=use_colour,
                unicodeboard=use_unicode)
    display_state(players_str, game)

    # Now wait for messages from the sever and respond accordingly
    while True:
        msg = server.recv(M.TURN | M.UPD8 | M.OVER | M.ERRO)
        if msg['mtype'] is M.TURN:
            # it's our turn!
            out("your turn!", depth=-1, clear=True)
            display_state(players_str, game)

            # decide on action and submit it to server
            action = player.action()
            server.send(M.ACTN, action=action)

        elif msg['mtype'] is M.UPD8:
            # someone made a move!
            colour = msg['colour']
            action = msg['action']
            # update our local state,
            out("receiving update", depth=-1, clear=True)
            game.update(colour, action)
            display_state(players_str, game)
            player.update(colour, action)
            # then notify server we are ready to continue:
            server.send(M.OKAY)

        elif msg['mtype'] is M.OVER:
            # the game ended!
            return msg['result']

        elif msg['mtype'] is M.ERRO:
            # seems like the server encountered an error, but not
            # with our connection
            raise ServerEncounteredError(msg['reason'])
Exemplo n.º 4
0
def connect_and_play(player, options, out):
    # SET UP SERVER CONNECTION
    out.section("connecting to battleground")
    # attempt to connect to the server...
    out.comment("attempting to connect to the server...")
    server = Server.from_address(options.host, options.port)
    out.comment("connection established!")

    # FIND A GAME
    # we would like to play a game!
    if options.channel:
        channel_str = f"channel '{options.channel}'"
    else:
        channel_str = "open channel"
    out.comment(
        f"submitting game request as '{options.name}' in {channel_str}...")
    server.send(M.PLAY, name=options.name, channel=options.channel)
    server.recv(M.OKAY)
    out.comment("game request submitted.")
    # wait for the server to find a game for us...
    out.comment(f"waiting for opponents in {channel_str}...")
    out.comment("(press ^C to stop waiting)")
    # (wait through some OKAY-OKAY msg exchanges until a GAME message comes---
    # the server is asking if we are still here waiting, or have disconnected)
    gamemsg = server.recv(M.OKAY | M.GAME)
    while gamemsg['mtype'] is not M.GAME:
        server.send(M.OKAY)
        gamemsg = server.recv(M.OKAY | M.GAME)
    # when we get a game message, it's time to play!
    out.comment("opponents found!")
    out.comment("red player:  ", gamemsg['red'])
    out.comment("green player:", gamemsg['green'])
    out.comment("blue player: ", gamemsg['blue'])

    # PLAY THE GAME
    # Set up a new Chexers game and initialise our player.
    game = Chexers(logfilename=options.logfile,
                   debugboard=options.verbosity > 2)

    out.section("initialising player")
    out.comment("waiting for colour assignment...")
    initmsg = server.recv(M.INIT | M.ERRO)
    if initmsg['mtype'] is M.ERRO:
        erromsg = initmsg
        out.section("connection error")
        out.print(erromsg['reason'])
        return
    out.comment("playing as", initmsg['colour'], pad=1)
    out.comment("initialising your player class...")
    player.init(initmsg['colour'])
    out.comment("ready to play!")
    server.send(M.OKAY)

    players = format_players(gamemsg, player.colour)

    # Display the initial state of the game.
    out.section("game start", clear=True)
    out.comment("displaying game info:")
    out.comments(players, pad=1)
    out.comments(game, pad=1)

    # Now wait for messages from the sever and respond accordingly:
    while True:
        msg = server.recv(M.TURN | M.UPD8 | M.OVER | M.ERRO)
        if msg['mtype'] is M.TURN:
            # it's our turn!
            out.section("your turn!", clear=True)
            out.comment("displaying game info:")
            out.comments(players, pad=1)
            out.comments(game, pad=1)

            # decide on action and submit it to server
            action = player.action()
            server.send(M.ACTN, action=action)

        elif msg['mtype'] is M.UPD8:
            # someone made a move!
            colour = msg['colour']
            action = msg['action']
            # update our local state,
            out.section("receiving update", clear=True)
            game.update(colour, action)
            out.comment("displaying game info:")
            out.comments(players, pad=1)
            out.comments(game, pad=1)
            player.update(colour, action)
            # then notify server we are ready to continue:
            server.send(M.OKAY)

        elif msg['mtype'] is M.OVER:
            # the game ended! either legitmately or through some
            # game error (e.g. non-allowed move by us or opponent)
            out.section("game over!")
            out.print(msg['result'])
            break

        elif msg['mtype'] is M.ERRO:
            out.section("connection error")
            out.print(msg['reason'])
            break
Exemplo n.º 5
0
def connect_and_play(
    player,
    name,
    channel,
    host,
    port,
    log_filename=None,
    out_function=None,
    print_state=True,
    use_debugboard=False,
    use_colour=False,
    use_unicode=False,
):
    """
    Connect to and coordinate a game with a server, return a string describing
    the result.

    Parameters:
    * player         -- Your player's wrapped object (supporting 'init',
                        'update' and 'action' methods).
    * name           -- Your player's name on the server
    * channel        -- The matchmaking channel string
    * host           -- The server address
    * port           -- The server port
    * log_filename   -- If not None, log all game actions to this path.
    * print_state    -- If True, print a picture of the board after each
                        update.
    * use_debugboard -- If True, use a larger board during updates (if
                        print_state is also True).
    * use_colour     -- Use ANSI colour codes for output.
    * use_unicode    -- Use unicode symbols for output.
    """
    # Configure behaviour of this function depending on parameters:
    if print_state:

        def display_state(players_str, game):
            comment("displaying game info:")
            comment(
                _RENDER(
                    game,
                    message=players_str,
                    use_debugboard=use_debugboard,
                    use_colour=use_colour,
                    use_unicode=use_unicode,
                ),
                depth=1,
            )

    else:

        def display_state(players_str, game):
            pass

    # Set up a connection with the server
    comment("connecting to battleground", depth=-1)
    comment("attempting to connect to the server...")
    server = Server.from_address(host, port)
    comment("connection established!")

    # Wait for some matching players
    comment("looking for a game", depth=-1)
    channel_str = f"channel '{channel}'" if channel else "open channel"
    comment(f"submitting game request as '{name}' in {channel_str}...")
    server.send(M.PLAY, name=name, channel=channel)
    server.recv(M.OKAY)
    comment("game request submitted.")
    comment(f"waiting for opponents in {channel_str}...")
    comment("(press ^C to stop waiting)")
    # (wait through some OKAY-OKAY msg exchanges until a GAME message comes---
    # the server is asking if we are still here waiting, or have disconnected)
    gamemsg = server.recv(M.OKAY | M.GAME)
    while gamemsg["mtype"] is not M.GAME:
        server.send(M.OKAY)
        gamemsg = server.recv(M.OKAY | M.GAME)
    # when we get a game message, it's time to play!
    comment("setting up game", depth=-1, clear=True)
    comment("opponents found!")
    for colour in COLOURS:
        comment(f"{colour} player:", gamemsg[colour])

    # Initialise the player
    comment("initialising player", depth=-1)
    comment("waiting for colour assignment...")
    initmsg = server.recv(M.INIT)
    comment("playing as", initmsg["colour"], depth=1)
    comment("initialising your player class...")
    player.init(initmsg["colour"])
    comment("ready to play!")
    server.send(M.OKAY)

    # Set up a new game and display the initial state and players
    comment("game start", depth=-1)
    players_str = format_players_str(gamemsg, player.colour)
    game = Game(log_filename)
    display_state(players_str, game)

    # Now wait for messages from the sever and respond accordingly
    while True:
        msg = server.recv(M.TURN | M.UPD8 | M.OVER | M.ERRO)
        if msg["mtype"] is M.TURN:
            # TODO: For simultaneous play, there's no need to display the
            # state again at the start of the turn...
            # comment("your turn!", depth=-1, clear=True)
            # display_state(players_str, game)
            # decide on action and submit it to server
            action = player.action()
            server.send(M.ACTN, action=action)

        elif msg["mtype"] is M.UPD8:
            player_action = msg["player_action"]
            opponent_action = msg["opponent_action"]
            comment("receiving update", depth=-1, clear=True)
            if player.colour == "upper":
                game.update(
                    upper_action=player_action,
                    lower_action=opponent_action,
                )
            else:
                game.update(
                    upper_action=opponent_action,
                    lower_action=player_action,
                )
            display_state(players_str, game)
            player.update(
                player_action=player_action,
                opponent_action=opponent_action,
            )
            # then notify server we are ready to continue:
            server.send(M.OKAY)

        elif msg["mtype"] is M.OVER:
            # the game ended!
            return msg["result"]

        elif msg["mtype"] is M.ERRO:
            # seems like the server encountered an error, but not
            # with our connection
            raise ServerEncounteredError(msg["reason"])