Ejemplo n.º 1
0
class Controller(object):
    def __init__(self, players, updater=None):
        self.players = players
        self.nplayers = len(players)
        self.state = GameState(self.nplayers)
        self.validator = Validator(self.state)
        self.logger = logging.getLogger(__name__)
        if updater is not None:
            self.update = ViewUpdater()
        else:
            self.update = updater

        self.delay = 0.5
        self.stalematecond = 2000
    def play(self):
        self.setup()
        while not self.gameEnded():
            currTime = int(round(time.time() * 1000))
            self.roll() #resource/bandit
            self.takeTurn() #actions
            self.nextPlayerTurn()
            while int(round(time.time() * 1000)) < currTime + 1000:
                pass
        self.end()

    def end(self):
        #tell everyone the game is over
        self.updateView()
        for player in self.players:
            player.getMove(self.state)

    def setup(self):
        # Send initial state for display
        self.update.sendTiles(self.state)
        #Decide first player randomly
        self.state.turn = random.randrange(0,self.nplayers)
        builtcount = 0
        turnorder = []
        for i in range(0, self.nplayers):
            turnorder.append((self.state.turn + i) % self.nplayers)
        turnorderbckwd = copy.deepcopy(turnorder)
        turnorderbckwd.reverse()
        turnorder += turnorderbckwd
        print "Turnorder: %s" %(str(turnorder))

        for i in range(0, self.nplayers*2):
            self.state.turn = turnorder[i]
            self.state.phase = "buildsettle"
            self.updateView()
            bs_move = self.getValidMove(self.state.turn)
            self.doMove(bs_move)
            self.state.phase = "buildroad"
            self.updateView()
            move = self.getValidMove(self.state.turn)
            self.doMove(move)
            #if this is second settle built do resource init
            if builtcount >= self.nplayers:
                for rec in self.state.getSurroundingResources(bs_move.location):
                    if rec != 'desert':
                        self.state.addResource(self.state.turn, rec, 1)

        #initial resource allocation

        self.state.phase = 'standard'

    def nextPlayerTurn(self):
        self.state.turn = (self.state.turn + 1) % self.nplayers

    def takeTurn(self):
        #loop action (trade, build, play, buy) until turn ended
        while not self.turnEnded():
            self.updateView()
            move = self.getValidMove(self.state.turn)
            self.doMove(move)
            self.state.updateAllScores()
        self.state.phase = 'standard'
        self.state.numturns += 1
    def updateView(self):
        self.update.sendGameState(self.state)

    def gameEnded(self):
        if self.state.maxPlayerScore() >= 10:
            self.state.phase = 'ended'
            self.state.phaseinfo = 'won'
            return True
        elif self.state.numturns >= self.stalematecond:
            self.state.phase = 'ended'
            self.state.phaseinfo = 'stalemate'
            return True
        else:
            return False


    def turnEnded(self):
        return self.state.phase == 'endturn'

    def roll(self):
        self.state.lastroll = random.randint(1,6) + random.randint(1,6)
        #self.updateView()
        if self.state.lastroll == 7:
            turn = self.state.turn
            #resource discard
            for i in range(0, self.nplayers):
                self.state.turn = i
                nresources = self.state.countResources(i)
                if nresources > 7:
                    reqresources = (nresources+1)/2
                    self.state.phase = "discard"
                    while nresources > reqresources:
                        # number you need to discard
                        self.state.phaseinfo = nresources - reqresources
                        # should we change whose turn it is in state?
                        move = self.getValidMove(i)
                        self.doMove(move)
                        nresources = self.state.countResources(i)
            self.state.turn = turn
            #robber movement
            self.moveRobber()
        else: #resource collection
            for (r,p,b) in self.state.getBuildings(self.state.lastroll):
                mult = 1 if b == 'settlement' else 2
                self.state.addResource(p, r, mult)
            #self.updateView()
        self.state.phase = 'standard'

    def moveRobber(self):
        self.state.phase = 'moverobber'
        move = self.getValidMove(self.state.turn)
        self.doMove(move)
        #list of playerid's next to robber
        adjplayers = self.state.getAdjacentPlayers(self.state.getRobberTile())
        if self.state.turn in adjplayers:
            adjplayers.remove(self.state.turn)
        #remove players who have no cards from adjacent list
        for i in xrange(len(adjplayers) - 1, -1, -1):
            if self.state.countResources(adjplayers[i]) == 0:
                del adjplayers[i]

        # Davis says to make code concise, use empty list as test for this
        # if statement otherwise he will hit irakli. I like irakli, so this list
        # is now the test for this if statement.
        if adjplayers:
            self.state.phaseinfo = adjplayers
            self.state.phase = 'chooseplayer'
            move = self.getValidMove(self.state.turn)
            self.doMove(move)

    def getValidMove(self, player):
        self.updateView()
        move = self.players[player].getMove(self.state)
        # loop until valid move receied
        while not self.isValid(move):
            self.logger.error("INVALID MOVE RECEIVED: Player %d, Move: %s, Phase %s" % (player,str(move), self.state.phase))
            move = self.players[player].getMove(self.state)
        return move

    def isValid(self, move):
        return self.validator.validateMove(move)

    def doMove(self, move):
        if move.typ == 'build':
            if move.structure == 'road':
                # 1 brick, 1 wood
                self.state.addRoad(move.playerid, move.location[0], move.location[1])
                if self.state.phase != 'buildroad':
                    self.state.removeResource(move.playerid, 'brick', 1)
                    self.state.removeResource(move.playerid, 'wood', 1)
            else:
                if move.structure == 'settlement':
                    # 1 brick, 1 wood, 1 wheat, 1 sheep settlement
                    if self.state.phase != 'buildsettle':
                        self.state.removeResource(move.playerid, 'wood', 1)
                        self.state.removeResource(move.playerid, 'wheat', 1)
                        self.state.removeResource(move.playerid, 'brick', 1)
                        self.state.removeResource(move.playerid, 'sheep', 1)
                elif move.structure == 'city':
                    # 2 wheat, 3 ore city
                    self.state.removeResource(move.playerid, 'wheat', 2)
                    self.state.removeResource(move.playerid, 'ore', 3)
                else:
                    self.logger.error("Unrecognized build type %s" % move.structure)
                self.state.addBuilding(move.playerid, move.structure, move.location)
            # check to see if building changed longest road count
            l = self.state.getLongestRoads()
            currentlongest = 0
            if self.state.longestroad is not None:
                currentlongest = l[self.state.longestroad]
            newlongestid = self.state.longestroad
            for i in xrange(0, self.nplayers):
                if l[i] > currentlongest:
                    newlongestid = i
                    currentlongest = l[i]
            #need to check if road breaking resulted in a tie
            if newlongestid != self.state.longestroad:
                if currentlongest<5:
                    self.state.longestroad = None
                elif l.count(currentlongest) != 1:
                    self.state.longestroad = None
                else:
                    self.state.longestroad = newlongestid
            # update remaining building count
            self.state.updateRemaining(move.playerid)
            #self.updateView()
        elif move.typ == 'trade':
            self.logger.error("TRADE MOVE NOT SUPPORTED")
        elif move.typ == 'navaltrade':
            self.state.removeResource(move.playerid,move.offer,4)
            self.state.addResource(move.playerid,move.want,1)
        elif move.typ == 'robber':
            #set robber tile
            self.state.setRobberTile(move.location)
        elif move.typ == 'takecard':
            # Remove card from target, add to initiator
            rectoremove = self.state.getRandomResource(move.target)
            self.state.removeResource(move.target, rectoremove, 1)
            self.state.addResource(move.playerid, rectoremove, 1)
            #self.updateView()
        elif move.typ == 'playcard':
            #yell when things are important
            self.logger.error("PLAY CARD MOVE NOT SUPPORTED")
        elif move.typ == 'discard':
            # Need to add ability to discard more than one at a time
            self.state.removeResource(move.playerid, move.card, 1)
        elif move.typ == 'endturn':
            self.state.phase = 'endturn'