8
\$\begingroup\$

In KoTH (and possibly other problems), you may want to be able to have 2 way communication with other programs, and for all of them to be persistent (they stay alive, waiting for information, and can return information)

This is not simple code to write.

Hence, I am looking to build a library of different sets of code that will take care of this for you.

Please post:

  1. How it works (over a network, using STDIN/STDOUT)
  2. How to use it in a controller program
  3. How a submission program will interact with it.
  4. The code
\$\endgroup\$
  • \$\begingroup\$ I'm also looking to make/contribute to/use a KotH controller. I would specifically like to see one that can keep all contestant programs persistent, but freeze them with a system call when it is not their turn, so that the bot whose turn it is doesn't have to share the CPU with them. Would this be best as a separate meta post or is it something you would consider generally useful to include here? \$\endgroup\$ – trichoplax Aug 17 '14 at 18:23
  • 1
    \$\begingroup\$ I think including it here would be useful. \$\endgroup\$ – Nathan Merrill Aug 17 '14 at 18:31
2
\$\begingroup\$

Python

This controller pipes to/from STDIN/STDOUT.

In order to use it, you must:

  1. Have a directory bots in the same directory as your controller
  2. For each bot, create another folder with the bot's name within bots
  3. In each folder, create a command.txt containing a line with the command of how to run the bot. (Ex: python bad_bot.py)
  4. Place the bot (and any additional files) in the folder
  5. Call read_players() in your controller, which will initialize each bot, and return a list of controllers for each of them.
  6. A controller has two methods, send_message(str) sends a string message to the bot and get_response() returns a string message from the bot.

The bot will use STDIN/STDOUT to get input/output.

The code is on Pastebin

\$\endgroup\$
  • \$\begingroup\$ I have a few improvements upon this, will post another answer soon. \$\endgroup\$ – Ray Aug 7 '14 at 20:16
2
\$\begingroup\$

Python 3.2+

This library currently only provides the controller. The clients(player bots) should use stdin/stdout to communicate with the controller. It uses Python 3's concurrent.futures library to implement the timeout controll. You can find it on this github repo.

Features

  • Collect players from specified directory. Support exclusion, this is useful when there're some players have problem and you want to disqualify them temporarily.
  • Send text message to clients
  • Receive a line of text message from client, with timeout.
  • Batch sending/receiving. Batch receiving is especially useful since receiving from different clients with timeout can be tricky to implement. A example case is that suppose the timeout is 100ms, the first client can only use 100ms but the second one may used 180ms(<200ms) without being killed, which is incorrect.
  • Kill clients.
  • Rearrange clients' order, useful when running position dependent game.

Using the Controller

  1. Create the instance controller
  2. Call controller.collect(directory, command_name, exclude=[]) to spawn clients.
  3. To send message to all clients, use controller.send_all(message)
  4. To receive message from all clients, use controller.receive_all(timeout)
  5. To iterate through the alive clients, use for client in controllers.iter_alive():
  6. With a single client, you can call:
    • send
    • receive
    • kill
  7. To kill all clients, use controller.kill_all().

Example: RockPaperScissorsGame

This can also be found in the testcases.

from kothlib import controller

class RockPaperScissorsGame:
    valid_choices = ('rock', 'paper', 'scissors')
    wins = {'rock': 'paper', 'paper': 'scissors', 'scissors': 'rock'}

    def __init__(self):
        self._controller = controller.Controller()

    def start(self, rounds):
        controller = self._controller
        controller.collect('bots', 'command.txt')
        controller.sort()
        scores = {client: 0 for client in controller}
        for round in range(rounds):
            print('-' * 80)
            print('round', round)
            print('players:', [client.name for client in controller.iter_alive()])
            print('send: choose')
            controller.send_all('choose')
            controller.receive_all(timeout=1.0)
            choices = set()
            for client in controller.iter_alive():
                choice = client.result
                if choice not in self.valid_choices:
                    continue
                choices.add(choice)
                print(client.name, client.result)
            if len(choices) == 2:
                choice1, choice2 = choices
                winner_choice = choice2 if self.wins[choice1] == choice2 else choice1
                for client in controller.iter_alive():
                    if client.result == winner_choice:
                        scores[client] += 1
        controller.send_all('quit')
        for client, score in sorted(scores.items(), key=lambda x: x[1]):
            print(client.name, score)
        print('Game finished')
        controller.receive_all(timeout=1.0)
        controller.kill_all()
RockPaperScissorsGame().start(10)
\$\endgroup\$
  • \$\begingroup\$ @githubphagocyte Thanks. The code on github is fine. I changed it a bit after I wrote this answer. \$\endgroup\$ – Ray Sep 1 '14 at 19:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .