Esempio n. 1
0
class Monopoly():
    def __init__(self, pnames):
        """
        :param pnames: An Array. Name of the players as Strings
        """
        self.board = Board()
        self.players = tuple([Player(pn, self.board, self) for pn in pnames])
        self.plookup = {p.getId(): p for p in self.players}
        self.lastRoll = None
        self.p = None
        self.getFirstPlayer()
        self.state = 0

    def getFirstPlayer(self):
        """
        Set the current player index if not already

        """
        if not self.p:
            self.p = rd.randrange(0, len(self.players))

    def getCurPlayer(self):
        """
        Get current player's object method

        Return the current player's Player object based on the current player index (self.p)

        :return: A Player object. The current player
        """
        return self.players[self.p]

    def roll(self):
        """
        Dice roll method

        Roll a double dice, and return the result

        :return: A Tuple contains the sum of the dice and a subtuple containing the value of two dices
        """
        d1 = rd.randint(1, 6)
        d2 = rd.randint(1, 6)
        self.lastRoll = d1 + d2
        signal(SIG_ROLL, (d1 + d2, (d1, d2)))
        return d1 + d2, (d1, d2)

    def getBoard(self):
        """
        Get board method

        Return the board associated with the game

        :return: a Board object
        """
        return self.board

    def setState(self, new_state):
        """
        Set game state method

        Set the game state to new_state

        :param new_state: An Integer. The new state value to be set as the game's state
        """
        self.state = new_state

    def isState(self, test):
        """
        Check game state method

        Return True if the current state is equal to test, False if otherwise

        :param test: An Integer. The state value to be compared with the game's state
        :return: A Boolean value
        """
        return self.state == test

    def move(self, x, index=False):
        """
        "Smart" move method

        This method takes in either a step, index or Slot object as x and move the current player to the appropriate
        slot.

        :param x: An Integer or Slot object
        :param index: A Boolean value. True if x: Integer is an index value, False if a step value. Unused if x is a
        Slot object
        """
        board = self.getBoard()
        player = self.getCurPlayer()
        if type(x) == int:
            if not index:
                newIdx, oldIdx = board.move(player, x)
                if x <= 0:
                    return
            else:
                newIdx, oldIdx = board.moveToIndex(player, x)
        else:
            newIdx, oldIdx = board.moveTo(player, x)
        # Pay salary
        if newIdx < oldIdx:
            pay(BANK, SALARY, player)

    def updateNextPlayer(self):
        """
        Player switching method

        Update the next player on the list as the current player.
        """
        self.p = (self.p + 1) % self.getPlayerCount()

    def sendToJail(self):
        """
        Send to jail method

        Send the current player to Jail, and set the status as "in jail".
        """
        player = self.getCurPlayer()
        signal(SIG_GOTOJAIL, (player.hasJFC(), ))
        self.board.moveTo(player, self.board.getJail())
        if not player.hasJFC():
            player.setInJail(True)
            player.resetJTL()
        else:
            player.popJFC()

    def cardExec(self, card):
        """
        Card action execute method

        Execute a card based on its intents. Intents are set flags bit in accordance to the intent flags in flags.py
        Once an intent has been establish, it will execute appropriate functions.

        Is this the best way to process cards? Probably not
        Does it work? Yes!

        :param card: A Card object. The card to be executed
        """
        tups = card.getAction()
        player = self.getCurPlayer()
        board = self.getBoard()
        for t in tups:
            intent, param = t
            if MOVE & intent:
                if NEAREST_RAIL & intent or NEAREST_UTIL & intent:
                    indices = [
                        idx for _, idx in (RAILROAD if NEAREST_RAIL
                                           & intent else UTILITY)
                    ]
                    indices.sort()
                    curIdx = player.getSlot().getIndex()
                    if curIdx > max(indices):
                        self.move(indices[0], index=True)
                    else:
                        res = next(i for i in indices if i > curIdx)
                        self.move(res, index=True)
                elif BACK & intent:
                    self.move(-3)
                elif JAIL & intent:
                    self.sendToJail()
                else:
                    self.move(board[param])
            elif CHECK & intent:
                if ROLL & intent:
                    self.roll(
                    )  # TODO: Optimize. This is redundant if util is owned by current player.
                self.check(param)
            elif PAY & intent:
                if OTHERS & intent:
                    for payee in self.players:
                        if payee != player:
                            pay(player, param,
                                payee) if not SELF & intent else pay(
                                    payee, param, player)
                elif SELF & intent:
                    pay(BANK, param, player)
                elif PROP & intent:
                    numHouses, numHotels = player.getBuildingCount()
                    feeHouse, feeHotel = param
                    total = numHouses * feeHouse + numHotels * feeHotel
                    pay(player, total, BANK)
                else:
                    pay(player, param, BANK)

    def whoNext(self):
        """
        Get current player's name method

        Return the current player's name.

        :return: A String. The current player's name
        """
        return self.getCurPlayer().getName()

    def getPlayerCount(self):
        """
        Get number of player method

        Return the number of players in the game

        :return: An Integer. The number of players
        """
        return len(self.players)

    def getState(self):
        """
        Get game's state method

        Return the current state of the game

        :return: An Integer. The current state of the game
        """
        return self.state

    def getCurrentPlayerData(self):
        """
        Get data of the current player method

        Return a snapshot of the current player's data

        :return: A dict object. The data of the current player
        """

        player = self.getCurPlayer()
        return player.getData()

    def getAllPlayerData(self, by_uuid=False):
        """
        Get data of all players method

        Return snapshots of all players' data

        :param by_uuid: A Boolean value. If True, the key of the return dict object will be the player's UUID
        :return: A dict object. The data of all player. Key will be the names of players by default
        """
        ret = {}
        for p in self.players:
            next_p = p.getData()
            if by_uuid:
                ret[next_p["id"]] = next_p
            else:
                ret[next_p["name"]] = next_p
        return ret

    def getData(self):
        """
        Return a snapshot of the game's data

        :return: A dict object. The data of the board
        """
        ret = self.getBoard().getData()
        ret["players"] = {}
        for p in self.players:
            ret["players"][p.getName()] = p.getData()
        return ret