예제 #1
0
    def setUp(self):
        self.com = MockCom(self)
        self.game = Game(self.com, 3, 4, 30, 30, True)

        self.game.dealer = MockDealer(self)
        self.game.setup_new_game()
        self.game.dealer = MockDealer(self)
        self.dealer = self.game.dealer
def runWebServer(host, port, quiet):
    """
	Install the logger and run the webserver
	"""

    # add a logger wrapper for bottle (in order to log its activity)
    # See http://stackoverflow.com/questions/31080214/python-bottle-always-logs-to-console-no-logging-to-file
    def log_to_logger(fn):
        """	Wrap a Bottle request so that a log line is emitted after it's handled."""
        @wraps(fn)
        def _log_to_logger(*_args, **_kwargs):
            actual_response = fn(*_args, **_kwargs)
            weblogger.info('%s %s %s %s' %
                           (request.remote_addr, request.method, request.url,
                            response.status))
            return actual_response

        return _log_to_logger

    # update the template paths so that in priority,
    # it first looks in <gameName>/server/templates/ and then in CGS/server/templates
    TEMPLATE_PATH.append('games/' + Game.getTheGameName() +
                         '/server/templates/')
    TEMPLATE_PATH.reverse()
    # add the base url to all the templates
    #Jinja2Template.defaults['base_url'] = 'http://%s:%s/' % (host, port)
    Jinja2Template.defaults['base_url'] = '/'
    # add the game name to all the templates (for page title)
    Jinja2Template.defaults['GameName'] = Game.getTheGameName()
    # Start the web server
    install(log_to_logger)
    weblogger.message('Run the web server on port %d...', port)

    default_app(
    ).catchall = True  # all the exceptions/errors are catched, and re-routed to error500
    run(host=host,
        port=port,
        quiet=quiet,
        server='gevent',
        handler_class=WebSocketHandler)
예제 #3
0
def create_new_game():
    """
	Receive the form to create a new game
	-> create the game (ie runPhase it)
	"""
    # get Players
    player1 = RegularPlayer.getFromName(request.forms.get('player1'))
    player2 = RegularPlayer.getFromName(request.forms.get('player2'))

    # !TODO: add some options (timeout, seed, etc.) in the html, and send them to the constructor
    try:
        # the constructor will check if player1 and player2 are available to play
        # no need to store the game object created here
        Game.getTheGameClass()(player1, player2)

    except ValueError as e:
        # !TODO: redirect to an error page
        # TODO: log this
        return 'Error. Impossible to create a game with ' + str(
            request.forms.get('player1')) + ' and ' + str(
                request.forms.get('player2')) + ': "' + str(e) + '"'
    else:
        redirect('/')
예제 #4
0
def game(gameName):
    """Returns the webpage of a game
	<gameName> is the name of the game
	If the name is not valid, the answer with the noObject page
	"""
    g = Game.getFromName(gameName)

    if g:
        try:
            displayName = g.getCutename()
        except NotImplementedError:
            displayName = gameName
        return template('game/Game.html',
                        host=Config.host,
                        webPort=Config.webPort,
                        gameName=gameName,
                        displayName=displayName,
                        player1=g.players[0].HTMLrepr(),
                        player2=g.players[1].HTMLrepr())
    else:
        return template('noObject.html', className='game', objectName=gameName)
예제 #5
0
def new_tournament():
    """
	Page to create a new tournament
	Build from HTMLFormDict class method of TournamentMode (build from all the tournament modes)
	"""
    return Tournament.HTMLFormDict(Game.getTheGameName())
    args = docopt(usage)
    if (not args['--debug']) and (not args['--dev']) and (not args['--prod']):
        args['--prod'] = True
    args['--port'] = int(args['--port'])
    args['--web'] = int(args['--web'])
    gameName = args['<gameName>']

    # import the <gameName> module and store it (in Game)
    try:
        mod = import_module('games.' + gameName + '.server.' + gameName)
        if gameName not in mod.__dict__:
            print(Fore.RED + "Error: The file `games/" + gameName +
                  "/server/" + gameName + ".py` must contain a class named `" +
                  gameName + "`." + Fore.RESET)
            quit()
        Game.setTheGameClass(mod.__dict__[gameName])
    except ImportError as e:
        print(Fore.RED + "Error: Impossible to import the file `games/" +
              gameName + "/server/" + gameName + ".py`." + Fore.RESET)
        print(e)
        quit()

    # configure the loggers
    logger = configureRootLogger(args)

    # Start !
    mode = 'prod' if args['--prod'] else 'dev' if args['--dev'] else 'debug'
    logger.message("")
    logger.message("#=====================================================#")
    logger.message("# Coding Game Server is going to start (mode=`%s`) #" %
                   mode)
예제 #7
0
    def waitForGame(self):
        """
		Waits for a message "WAIT_GAME %s" and then wait for a game (with an Event)
		%s is a string like (options is like "key1=value1 key2=value2 ...")
		- "{options}": regular game (with options)
		- "TOURNAMENT NAME {options}": tournament
		- or "NAME {options}": play agains training player
        Returns nothing
		"""
        # !TODO: normalize the options: should be "[options]", "TRAINING <name> [options]" or "TOURNAMENT <name> [options]"
        # get the WAIT_GAME message
        data = self.receiveData()
        if not data.startswith("WAIT_GAME"):
            self.sendData("Bad protocol, should send 'WAIT_GAME %s' command")
            raise ProtocolError(
                "Bad protocol, should send 'WAIT_GAME %s' command")

        # parse the game type (in the form "TOURNAMENT NAME key1=value1..." or "NAME key1=value1 key2=value2")
        trainingPlayerName = ""
        tournamentName = ""
        options = {}
        try:
            terms = shlex.split(data[10:])
            if terms:
                if "=" in terms[0]:
                    trainingPlayerName = ""
                    tournamentName = ""
                    options = dict([token.split('=') for token in terms])
                elif terms[0] == 'TOURNAMENT':
                    trainingPlayerName = ""
                    tournamentName = terms[1]
                    options = dict([token.split('=') for token in terms[2:]])
                else:
                    trainingPlayerName = terms[0]
                    tournamentName = ""
                    options = dict([token.split('=') for token in terms[1:]])
        except ValueError:
            strerr = "The string sent with 'WAIT_GAME' is not valid (should be '{options}'," \
                     " 'NAME {options}' or 'TOURNAMENT NAME {options}', but is '%s' instead)"
            self.sendData(strerr)
            raise ProtocolError(strerr)

        if trainingPlayerName:
            # Create a particular Game
            try:
                # create game (no need to store it in a variable)
                g = Game.getTheGameClass().gameFactory(trainingPlayerName,
                                                       self._player, options)
            except ValueError as err:
                self.sendData(
                    "The training player sent by '%s' command is not valid (%s)"
                    % (data, err))
                raise ProtocolError(
                    "The training player sent by '%s' command is not valid (%s)"
                    % (data, err))
            # log it
            self.logger.debug(
                "The game %s starts with training player `%s` and options=%s" %
                (g.name, trainingPlayerName, options))
        elif tournamentName:
            try:
                # register the player in the tournament
                Tournament.registerPlayer(self._player, tournamentName)
            except ValueError as err:
                self.sendData("The tournament '%s' cannot be joined: %s" %
                              (tournamentName, err))
                raise ProtocolError(
                    "The tournament '%s' cannot be joined: %s" %
                    (tournamentName, err))

        # just send back OK
        self.sendData("OK")

        # wait for the Game
        # and send every second a "NOT_READY" if the game do not start
        # in order to know if the client has disconnected
        gameHasStarted = self._player.waitForGame(5)
        while not gameHasStarted:
            self.sendData("NOT_READY")
            gameHasStarted = self._player.waitForGame(3)

        # now send the game name
        self.sendData(self.game.name)

        # now send the game sizes
        self.sendData(self.game.getDataSize())
    def runPhase(self, **kwargs):
        """Launch a phase of the tournament
		"""
        # check if a phase is not already running
        if self.isPhaseRunning:
            # do noting, since a phase is already running
            return

        # first launch ?
        if not self.hasBegan:
            # we first need to get the list of 2-tuple (player1's name, player2's name)
            # of players who will play together in the phase
            try:
                phase, self._matches = next(self._matchGen)
            except StopIteration:
                self.endTournament()
            else:
                self.newPhase(phase)
        else:
            # otherwise, start a new phase
            self.newPhase()

        # build the dictionary of the games (pair of players' name -> list of score (tuple) and current game
        # (we remove fake players with "" as name)
        self._games = {(pName1, pName2): [[0, 0], None]
                       for pName1, pName2 in self._matches
                       if pName1 and pName2}
        # run the games
        for self._round in range(1, 2 * self.nbRounds4Victory + 1):

            for (pName1, pName2), (score, _) in self._games.items():

                if max(score) < self.nbRounds4Victory:
                    # choose who starts (-1 for random, ie for the last round)
                    start = (
                        self._round - 1
                    ) % 2 if self._round < 2 * self.nbRounds4Victory else -1

                    # run the game only if the two players are here (otherwise, one wins directly)
                    player1, player2 = self._players[pName1], self._players[
                        pName2]
                    if player1 and player2:

                        self._games[(pName1,
                                     pName2)][1] = Game.getTheGameClass()(
                                         player1,
                                         player2,
                                         start=start,
                                         tournament=self,
                                         **kwargs)
                        self.logger.info("The game `%s` vs `%s` starts",
                                         pName1, pName2)
                        self._queue.put_nowait(None)
                    else:
                        # one player is not playing anymore (disconnected), so the other wins
                        score = self._games[(pName1, pName2)][0]
                        if player1 is not None:
                            score[0] += 1
                        elif player2 is not None:
                            score[1] += 1
                        else:
                            # in the case where the 2 players are disconnected, the 1st win...
                            # !FIXME: introduce equality (the result of a game is either WIN, LOOSE or EQUALITY !)
                            score[start] += 1

            # update the websockets (no need to update everytime a game is added)
            self.sendUpdateToWebSocket()
            # and wait for all the games to end (before running the next round)
            self._queue.join()
            time.sleep(
                1
            )  # !!TODO: check why is not fully working when we remove this sleep....

        # update the scores
        self.updateScore()

        # Prepare the next list of 2-tuple (player1,player2) of players who will play in next phase
        try:
            phase, self._matches = next(self._matchGen)
        except StopIteration:
            # no more matches to run (end of the tournament)
            self.endTournament()
        else:
            self.endPhase(phase)

        # update data through websockets
        self.sendUpdateToWebSocket()
예제 #9
0
class TestGame(unittest.TestCase):
    def setUp(self):
        self.com = MockCom(self)
        self.game = Game(self.com, 3, 4, 30, 30, True)

        self.game.dealer = MockDealer(self)
        self.game.setup_new_game()
        self.game.dealer = MockDealer(self)
        self.dealer = self.game.dealer

    def tearDown(self):
        pass

    def test_chat(self):
        pass

    def test_join(self):
        # try to pass in a shitty name
        self.com.exeEvt("join", 1, "|shit")
        self.assertTrue(self.com.invalid["called"])
        self.assertEqual(self.com.invalid["p"][1], "|shit")
        self.com.reset_p()

        self.com.exeEvt("join", 3, "player1")

        self.com.exeEvt("join", 4, "player2")

        self.assertEqual(len(self.game.clients), 2)

        # now add 3rd player, check if it starts to count down
        self.com.exeEvt("join", 5, "player3")
        self.assertEqual(self.game.status, 1)

        started_time = self.game.count_time

        # now add 4th players, check if it resets the count down
        self.com.exeEvt("join", 10, "player4")
        self.assertNotEqual(self.game.count_time, started_time)
        started_time = self.game.count_time

        # now add 5th players, check if it politely ask the player to wait
        # and not reset the count down
        self.com.exeEvt("join", 11, "player5")
        self.assertEqual(self.game.count_time, started_time)
        self.assertTrue(self.com.wait["called"])
        self.assertEqual(self.com.wait["p"][0], 11)
        self.assertEqual(self.com.wait["p"][1], "player5")
        self.com.reset_p()

        # now try to put more player than the queue size
        # supposed to kick them out
        self.game.maxQueue = 4
        self.com.exeEvt("join", "player6", 14)
        self.assertTrue(self.com.kick["called"])
        self.assertEqual(self.com.kick["p"][0], 14)

    def test_check_time(self):

        self.game.check_time()

        self.com.exeEvt("join", 3, "player1")
        self.com.exeEvt("join", 4, "player2")
        self.com.exeEvt("join", 5, "player3")

        self.game.cd_join = 0
        self.game.check_time()
        self.assertTrue(self.dealer.sg_c["called"])
        self.assertEqual(self.dealer.sg_c["p"][0], 3)

        self.assertTrue(self.com.start["called"])
        self.assertEqual(self.com.start["p"][0], "player1,player2,player3")