Exemplo n.º 1
0
    def __init__(self,
                 bot_name=None,
                 server_ip="35.159.50.117",
                 server_port=9000,
                 buffer_size=1024,
                 max_message_timeout_count=5):
        """
        Creates a HighLevelBotAPI object.

        :param bot_name: The name of the Bot.
        :param server_ip: IP of the server.
        :param server_port: Port of the server.
        :param buffer_size: Size of the Buffer.
        """
        self.max_message_timeout_count = max_message_timeout_count
        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if bot_name:
            self._bot_name = bot_name
        else:
            self._bot_name = \
                ''.join(random.choice(string.ascii_lowercase) for _ in range(6))

        # Placeholders
        self._callback = lambda x: None
        self._main_thread = None
        self._stop_main = False
        self._gameplays = []
        self._token = ""

        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.DEBUG)
    def __init__(self,
                 base_save_path,
                 save_interval=100,
                 spectator_name="spectator",
                 rand_name_suffix=True,
                 server_ip="35.159.50.117",
                 server_port=9000,
                 buffer_size=1024):
        """
        Creates a GameLogger.

        :param str base_save_path: Base path of where to save the logs
        :param int save_interval: Saving after each interval
        :param str spectator_name: The name of the spectator.
        :param bool rand_name_suffix: Add a random suffix to the name. This enables two multiple spectators.
        :param str server_ip: IP of the server.
        :param int server_port: Port of the server.
        :param int buffer_size: Size of the Buffer.
        """
        self._save_path = Path(base_save_path) / Path(
            "mia_" + datetime.now().strftime("%d-%m-%Y_%H:%M:%S") + ".yaml")
        self._save_interval = save_interval

        # Placeholders
        self._rounds = []

        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if rand_name_suffix:
            self._spectator_name = spectator_name + "x" + \
                ''.join(random.choice(string.ascii_lowercase) for i in range(3))
        else:
            self._spectator_name = spectator_name

        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.DEBUG)

        self.start()
Exemplo n.º 3
0
    def __init__(self, bot_name="", show=True, tablefmt=None):
        """
        Creates a Scoreboard in the terminal.

        :param bot_name: The name of the Bot.
        :param show: Show the highscore in the terminal.
        """
        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if bot_name:
            self._bot_name = bot_name
        else:
            self._bot_name = \
                ''.join(random.choice(string.ascii_lowercase) for _ in range(6))

        self._highscore_table = "No highscore yet!"

        self._show = show
        self._tablefmt = tablefmt

        # Placeholders
        self._stats = []
        self.stop_main = False
Exemplo n.º 4
0
class MaexchenHighLevelBotAPI(object):
    def __init__(self,
                 bot_name=None,
                 server_ip="35.159.50.117",
                 server_port=9000,
                 buffer_size=1024,
                 max_message_timeout_count=5):
        """
        Creates a HighLevelBotAPI object.

        :param bot_name: The name of the Bot.
        :param server_ip: IP of the server.
        :param server_port: Port of the server.
        :param buffer_size: Size of the Buffer.
        """
        self.max_message_timeout_count = max_message_timeout_count
        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if bot_name:
            self._bot_name = bot_name
        else:
            self._bot_name = \
                ''.join(random.choice(string.ascii_lowercase) for _ in range(6))

        # Placeholders
        self._callback = lambda x: None
        self._main_thread = None
        self._stop_main = False
        self._gameplays = []
        self._token = ""

        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.DEBUG)

    def start(self):
        """ 
        Start the game for your bot (non blocking).
        It joins the game on the next possibility.
        """
        print("--- Starting")
        # Register
        self._udp_client.send_message(f"REGISTER;{self._bot_name}")
        msg = self._udp_client.await_message()
        if msg.startswith("REJECTED"):
            raise MaexchenRegisterError("--- Connection rejected")
        elif not msg.startswith("REGISTERED"):
            raise MaexchenRegisterError(
                f"--- Connection not accepted. Got: '{message}'")

        self._stop_main = False
        self._main_thread = threading.Thread(target=self._main_loop, args=())
        self._main_thread.start()
        print("--- Started")

    def register_callback(self, func):
        """ 
        Register a callback function which is called when its your turn.
        The callback function is called with a tuple of both claimed dice values.
        """
        print("--- Registering callback for bot " + self._bot_name +
              " to function " + str(func))
        self._callback = func

    def accuse(self):
        """ 
        Accuse the person before of lying.
        Return if the judgment was wright or wrong.
        This is exclusive to the `roll` function.
        """
        print("--- Accusing")
        self._udp_client.send_message(f"SEE;{self._token}")
        for message_timeout_count in range(self.max_message_timeout_count):
            message = self._udp_client.await_message()
            if message.startswith("PLAYER LOST;"):
                print(message)
                if message.endswith("CAUGHT_BLUFFING"):
                    return True
                if message.endswith("SEE_FAILED"):
                    return False
        raise MaexchenTimeoutError("Timeout while accusing!")

    def roll(self):
        """
        Rolls your dice. This is exclusive to the `accuse` function.
        """
        print("--- Rolling")
        self._udp_client.send_message(f"ROLL;{self._token}")

        for message_timeout_count in range(self.max_message_timeout_count):
            message = self._udp_client.await_message()
            if message.startswith("ROLLED;"):
                print(message)
                self._token = message.split(";")[2]
                dice = tuple(
                    [int(num) for num in message.split(";")[1].split(",")])
                return dice
        raise MaexchenTimeoutError("Timeout while waiting for ROLLED!")

    def announce(self, dice):
        """
        Announces a dice roll or lie.
        """
        print("--- Announcing " + str(dice))
        self._udp_client.send_message(
            f"ANNOUNCE;{dice[0]}, {dice[1]};{self._token}")

    def get_announced(self):
        """
        Retuns a list of all recently announced gameplays.

        :return: List of Tuples with the name and the value tuple.
        """
        return self._gameplays

    def close(self):
        """
        Closes the Bots connection.
        """
        print("--- Closing")
        self._stop_main = True
        self._main_thread.join()
        self._stop_main = False
        self._udp_client.send_message("UNREGISTER")
        _ = self._udp_client.await_commands("UNREGISTERED")
        print("--- Unregistered")
        self._udp_client.close()

    def _main_loop(self):
        """
        Runs the main loop which listens for messages from the server.
        """
        while not self._stop_main:
            message = self._udp_client.await_message()
            # Join the round
            if message.startswith("ROUND STARTING"):
                print(message)
                self._token = message.split(";")[1]
                self._udp_client.send_message(f"JOIN;{self._token}")
                self._gameplays = []

            if message.startswith("ANNOUNCED"):
                print(message)
                split = message.split(";")
                name = split[1]
                dice = tuple([int(num) for num in split[2].split(",")])
                self._gameplays.append((name, dice))

            if message.startswith("YOUR TURN"):
                print(message)
                self._token = message.split(";")[1]
                try:
                    if self._gameplays:
                        self._callback(self._gameplays[-1])
                    else:
                        self._callback(None)
                except MaexchenTimeoutError as e:
                    print("--- Skipped turn due to timeout error!")
                    continue
import random

import sys
from duckling.lib.udp import MaexchenUdpClient, MaexchenConnectionError

if __name__ == "__main__":

    random_name = "python-bot-" + str(random.randint(100, 9999))

    udp_client = MaexchenUdpClient()
    register_msg = "REGISTER;" + random_name
    udp_client.send_message(register_msg)
    print("CLIENT->SERVER: ", register_msg)

    while True:
        try:
            message = udp_client.await_message()
            print("SERVER->CLIENT: ", message)

            if message.startswith("ROUND STARTING"):
                token = message.split(";")[1]
                answer = "JOIN;" + token
                udp_client.send_message(answer)
                print("CLIENT->SERVER: ", answer)

            if message.startswith("YOUR TURN"):
                token = message.split(";")[1]
                answer = "SEE;" + token
                udp_client.send_message(answer)
                print("CLIENT->SERVER: ", answer)
Exemplo n.º 6
0
class MaexchenStat(object):
    def __init__(self, bot_name="", show=True, tablefmt=None):
        """
        Creates a Scoreboard in the terminal.

        :param bot_name: The name of the Bot.
        :param show: Show the highscore in the terminal.
        """
        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if bot_name:
            self._bot_name = bot_name
        else:
            self._bot_name = \
                ''.join(random.choice(string.ascii_lowercase) for _ in range(6))

        self._highscore_table = "No highscore yet!"

        self._show = show
        self._tablefmt = tablefmt

        # Placeholders
        self._stats = []
        self.stop_main = False

    def start(self):
        """
        Start the game for your bot (non blocking).
        It joins the game on the next possibility.
        """
        print("--- Starting")
        # Register
        self._udp_client.send_message(f"REGISTER_SPECTATOR;{self._bot_name}")
        msg = self._udp_client.await_message()
        if msg.startswith("REJECTED"):
            raise MaexchenRegisterError("--- Connection rejected")
        elif not msg.startswith("REGISTERED"):
            raise MaexchenRegisterError(
                f"--- Connection not accepted. Got: '{msg}'")

        try:
            self._main_loop()
        except KeyboardInterrupt:
            self.close()
            exit(0)

    def close(self):
        """
        Closes the Bots connection.
        """
        self.stop_main = False
        print("--- Closing", self._bot_name)
        self._udp_client.send_message("UNREGISTER")
        print("--- Unregistered")
        self._udp_client.close()

    def get_highscore_table(self):
        """
        Returns the highscore table
        """
        return self._highscore_table

    def _main_loop(self):
        """
        Runs the main loop which listens for messages from the server.
        """
        num_steps = 500
        while not self.stop_main:
            message = self._udp_client.await_message()
            # Join the round
            if message.startswith("SCORE"):
                if self._show:
                    os.system('clear')
                    print("\nScoreboard:")
                bot_dict = {}
                bots = message.split(";")[1]
                bots = bots.split(",")
                for bot in bots:
                    player, score = bot.split(":")
                    bot_dict[player] = int(score)

                self._stats.append(bot_dict)

                diff_dict = {}
                if len(self._stats) > num_steps:
                    temp_num_steps = num_steps
                else:
                    temp_num_steps = len(self._stats)

                for player in self._stats[-1].keys():
                    diff_dict[player] = (
                        self._stats[-1][player] -
                        self._stats[-temp_num_steps].get(player, 0))

                diff_dict = {
                    k: v
                    for k, v in sorted(diff_dict.items(),
                                       key=lambda item: item[1],
                                       reverse=True)
                }

                table = {"Bot Name": [], "Score": []}

                for bot in diff_dict:
                    if diff_dict[bot] > 0:
                        table["Bot Name"].append(bot)
                        table["Score"].append(diff_dict[bot])

                self._highscore_table = tabulate(
                    table,
                    tablefmt=self._tablefmt,
                    floatfmt=".4f",
                    headers=['Bot', f'Score (last {num_steps} Rounds)'])

                if self._show:
                    print(self._highscore_table)
class GameLogger():
    def __init__(self,
                 base_save_path,
                 save_interval=100,
                 spectator_name="spectator",
                 rand_name_suffix=True,
                 server_ip="35.159.50.117",
                 server_port=9000,
                 buffer_size=1024):
        """
        Creates a GameLogger.

        :param str base_save_path: Base path of where to save the logs
        :param int save_interval: Saving after each interval
        :param str spectator_name: The name of the spectator.
        :param bool rand_name_suffix: Add a random suffix to the name. This enables two multiple spectators.
        :param str server_ip: IP of the server.
        :param int server_port: Port of the server.
        :param int buffer_size: Size of the Buffer.
        """
        self._save_path = Path(base_save_path) / Path(
            "mia_" + datetime.now().strftime("%d-%m-%Y_%H:%M:%S") + ".yaml")
        self._save_interval = save_interval

        # Placeholders
        self._rounds = []

        self._udp_client = MaexchenUdpClient()

        # Set or generate the bot name
        if rand_name_suffix:
            self._spectator_name = spectator_name + "x" + \
                ''.join(random.choice(string.ascii_lowercase) for i in range(3))
        else:
            self._spectator_name = spectator_name

        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.DEBUG)

        self.start()

    def start(self):
        """ 
        Start the game for your spectator (non blocking).
        It joins the game on the next possibility.
        """
        print(f"LOGGING DATA to '{self._save_path}'...")
        self._udp_client.send_message(
            f"REGISTER_SPECTATOR;{self._spectator_name}")
        self._main_loop()

    def close(self):
        """
        Closes the Bots connection.
        """
        print("CLOSING CONNECTION...")
        self._udp_client.send_message("UNREGISTER")
        self._udp_client.close()
        print("CONNECTION CLOSED")
        self._save_data()
        print(f"LOG DATA saved to '{self._save_path}'")

    def _main_loop(self):
        """
            Runs the main loop which listens for messages from the server.
            """
        round_count = 0  # Used for save interval
        while True:
            try:
                message = self._udp_client.await_commands(["ROUND STARTED"
                                                           ])  # Round started
                idx = message.split(";")[1]
                players = message.split(";")[2].split(",")
                self._rounds.append(Round(idx, players))
                self._current_player_counter = 0
                self._listen_move()
                if round_count % self._save_interval == 0:
                    self._save_data()
                round_count += 1

            except KeyboardInterrupt:
                self.close()
                exit(0)

    def _listen_move(self):
        """
        Recursively listens to the game moves until round is finished.
        """
        message = self._udp_client.await_commands(["ANNOUNCED", "SCORE"])
        split = message.split(";")
        if split[0] == "SCORE":
            return
        move = Move()
        self._rounds[-1].add_move(move)
        players = self._rounds[-1].get_players()
        move.set_player(players[self._current_player_counter])
        move.set_announced(tuple([int(i) for i in split[2].split(",")]))
        self._current_player_counter = (self._current_player_counter +
                                        1) % len(players)

        message = self._udp_client.await_commands(
            ["ACTUAL DICE", "PLAYER ROLLS", "SCORE"])
        split = message.split(";")
        cmd = split[0]
        if cmd == "SCORE":
            return
        elif cmd == "ACTUAL DICE":
            move.set_accused(True)
            move.set_truth(tuple([int(i) for i in split[1].split(",")]))

        elif cmd == "PLAYER ROLLS":
            self._listen_move()

    def _save_data(self):
        print("Saving data...")
        data = [r.serialize() for r in self._rounds]
        with open(self._save_path, 'w') as save_file:
            yaml.dump(data, save_file)