예제 #1
0
class BlindChessRoot(BoxLayout):
    
    def initialsetup(self):  # called at the beginning of the game
        """ initialize the game state.  Called on the first button press."""
        self.createchessengine()
        self.purewhite   = ( 1,   1,  1, 1)
        self.brightwhite = (0.9,0.9,0.9, 1)
        self.lightgray   = (0.6,0.6,0.6, 1)
        self.darkgray    = (0.4,0.4,0.4, 1)   
        self.darkblack   = (0.1,0.1,0.1, 1)     
        self.pureblack   = ( 0,   0,  0, 1)
        self.ids["messageW"].text = 'Your Move'
        self.ids["messageB"].text = 'Black Move'
        self.setcancelandmovebuttons('cancel','move')
        self.blind = 1    # 1 means blind.  0 means show the pieces  
        self.sourcex = -1  # set the source and destination to none
        self.sourcey = -1 
        self.destx = -1
        self.desty = -1     
        self.resetbothmistakecounts()
        self.updateboardui()
        for x in range(0,8):
            for y in range(0,8):
               self.resetsquarebackground(x,y)
        self.whosemove = 'W' # white moves first
        self.setwidgetbackgroundcolors()
        self.ids['clockW'].text = "10:00"
        self.ids['clockB'].text = "10:00"
        self.ids['messageW'].font_size = '30dp'
        self.ids['messageB'].font_size = '30dp'
        self.cancelcount = 0 # pressing cancel 3 times in a row toggles self.blind
        self.resetcount  = 0 # pressing any board square 5 times in a row
                             # resets the game
        self.resetx = 0
        self.resety = 0
        self.clock = Clock.schedule_interval(self.updateclocks, 1)
        if self.whiteplayer == 'human':
            self.state = "looking for source"        
        else:
            self.state = "cpu turn to move"
            self.cpumove(0)
         
    def createchessengine(self):
        """ Creates the chess engine.  Maintains the game state and enforces move rules."""
        self.chessengine = ChessEngine() 
        
    def updateboardui(self): 
        """ Update the display to match the engine."""
        for x in range(0,8):
            for y in range(0,8):
                stringid = "but"+str(x)+str(y)
                colorpiece = self.chessengine.getpiece(x,y)
                buttonid = "but"+str(x)+str(y)
                if self.blind == 0 and colorpiece[0] != '0':
                    if colorpiece[0] == 'B':
                        self.ids[buttonid].color = self.pureblack
                    else:
                        self.ids[buttonid].color = self.purewhite
                    self.ids[buttonid].text = colorpiece[1]
                else:
                    self.ids[buttonid].text = ''
                    
    def setallfontsonecolor(self, color):
        """ Sets the button and counts to a color to alert the player something has happened."""
        self.ids['clockW'].color = color
        self.ids['clockB'].color = color
        self.ids['mistakecountW'].color = color                
        self.ids['mistakecountB'].color = color                
        self.ids['moveW'].color = color
        self.ids['moveB'].color = color
        self.ids['cancelW'].color = color
        self.ids['cancelB'].color = color
        
    def restoreallfonts(self):
        """ Restores the button and counts to their original color."""
        almostblack = (0.2,0.2,0.2,1)
        almostwhite = (0.8,0.8,0.8,1)
        self.ids['clockW'].color = almostwhite
        self.ids['clockB'].color = almostblack
        self.ids['mistakecountW'].color = almostwhite                
        self.ids['mistakecountB'].color = almostblack              
        self.ids['moveW'].color = self.darkgray
        self.ids['moveB'].color = self.lightgray
        self.ids['cancelW'].color = self.darkgray
        self.ids['cancelB'].color = self.lightgray
        
                   
    def getboardcolor(self,x,y):
        """ Returns the background color of a board square."""
        if (y%2 == 0 and x%2 == 0) or (y%2 == 1 and x%2 == 1):
            return self.darkgray
        else:
            return self.lightgray  
            
    def updateclocks(self,dt):
        """ Adds one second to the active board clock."""
        if self.whosemove == 'W':
            timestring = self.ids['clockW'].text
        else:
            timestring = self.ids['clockB'].text
            
        if timestring != '00:00':
            if timestring[4] != '0':
                timestring = timestring[0:4]+str(int(timestring[4])-1)
            else:
                if timestring[3] != '0':
                    timestring = timestring[0:3]+str(int(timestring[3])-1)+'9'
                else:
                    if timestring[1] != '0':
                        timestring = timestring[0]+str(int(timestring[1])-1)+timestring[2]+'59'
                    else:
                        timestring = str(int(timestring[0])-1)+'9:59'
        if self.whosemove == 'W':
            self.ids['clockW'].text = timestring
        else:
            self.ids['clockB'].text = timestring            
            
    def setwidgetbackgroundcolors(self):
        """ Sets the background color of the move and cancel buttons."""
        if self.whosemove == 'W': 
            blackcolor = self.darkgray
            whitecolor = self.brightwhite
        else:
            blackcolor = self.darkblack
            whitecolor = self.lightgray
        self.ids["moveB"].background_color = blackcolor
        self.ids["cancelB"].background_color = blackcolor
        self.ids["moveW"].background_color = whitecolor
        self.ids["cancelW"].background_color = whitecolor
        
    def resetsquarebackground(self,x,y):
        """ Resets a board square back to its original color."""
        buttonid = "but"+str(x)+str(y)
        self.ids[buttonid].background_color = self.getboardcolor(x,y)
        
    def setcancelandmovebuttons(self,canceltext,movetext):
        self.ids["moveB"].text = movetext
        self.ids["cancelB"].text = canceltext
        self.ids["moveW"].text = movetext
        self.ids["cancelW"].text = canceltext
         
        
    def resetbothmistakecounts(self):    
        labelidblack = "mistakecountB"
        labelidwhite = "mistakecountW"
        self.ids[labelidblack].text = str(0)
        self.ids[labelidwhite].text = str(0)
        
    def increasemistakecount(self,color):
        """ Increment the mistake count of the active player."""
        # read the mistake count and convert to a number
        labelid = "mistakecount"+color 
        mistakecount = int(self.ids[labelid].text) 
        mistakecount += 1 # increment
        self.ids[labelid].text = str(mistakecount) # convert to a string and update
        
    def updatebothmessages(self, message, colortodraw):
        """" Update the on screen message to both players."""
        colorvalue = self.purewhite
        if colortodraw == 'B' : colorvalue = self.pureblack
        self.ids['messageW'].text = message
        self.ids['messageB'].text = message
        self.ids['messageW'].color = colorvalue
        self.ids['messageB'].color = colorvalue
        
    def updatemessage(self,message,colortoupdate,colortodraw):
        """ Update the on screen message of one of the players."""
        labelid = "message"+colortoupdate 
        self.ids[labelid].text = message
        if colortodraw == 'W':
            self.ids[labelid].color = self.purewhite
        else:
            self.ids[labelid].color = self.pureblack
    
    def resetaftermove(self):
        """ Reset the board after a move."""
        # reset both the cursors ui
        if self.sourcex != -1:
            self.resetsquarebackground(self.sourcex,self.sourcey)
        if self.destx != -1:    
            self.resetsquarebackground(self.destx,self.desty)
        # reset the source and destination
        self.sourcex = -1
        self.sourcey = -1
        self.destx = -1
        self.desty = -1
        # redraw the board
        self.updateboardui()
        # reset the message colors
        self.restoreallfonts()
        # set the state
        self.state = "looking for source"
        if ((self.whiteplayer == 'cpu' and self.whosemove == 'W') or 
                (self.blackplayer == 'cpu' and self.whosemove == 'B')):
            self.state = "cpu turn to move"
            self.cpumove(0)

        
    def checkforpawnpromotion(self, color):
        """ Check if a pawn needs to be promoted and prompt the user if they want a queen."""
        # check if we need to do pawn promotion
        # we will start with Queen
        # The order we will present the promotion options is
        # Q, N, R, B, 
        x,y = self.chessengine.checkforpawnpromotion(color)
        if x == -1: return False
        self.promotex = x # save pawn promotion coordinates for later
        self.promotey = y 
        # redraw the board
        self.updateboardui()
        self.updatemessage('Promote Queen?',color,color)
        self.state = "Promote Queen?"
        return True
        
    def promoteprawn(self, color, piece):
        """ Promote a pawn to the selected piece."""
        self.chessengine.promotepawn(color,piece,self.promotex,self.promotey)
        self.movestring += piece 
        oppcolor = 'B'
        if color == 'B': oppcolor = 'W'
        if self.chessengine.checkifincheck(oppcolor,self.chessengine.board): self.movestring += '+'
        self.updatebothmessages(self.movestring,self.whosemove)
        if self.whosemove == 'B': # switch the players turn
            self.whosemove = 'W'
        else:
            self.whosemove = 'B'
        self.setwidgetbackgroundcolors()
        self.resetaftermove()
        if self.chessengine.checkifincheck(self.whosemove,self.chessengine.board):
            self.setallfontsonecolor((0,0,1,1)) # turn the fonts blue if in check        

    def resign(self):
        self.state = 'CPU resigns'
        if self.whosemove == 'B':  message = "BLACK RESIGNS"
        else: message = "WHITE RESIGNS"
        self.updatebothmessages(message, self.whosemove)   # change the message to BLACK or WHITE RESIGNS
        self.setallfontsonecolor((0,1,0,1))  # set the fonts to green
        
    
    def cpumove(self,dt):
        whosemove = self.whosemove
        move = self.chessengine.getcomputermoveincremental(whosemove)
        if move == 'RESIGN':
            self.resign()
            return   # user will need to reset the board to exit this state.
        if move == False:
            Clock.schedule_once(self.cpumove,0.1)
            return
        
        self.sourcex = move[0]
        self.sourcey = move[1]
        self.destx = move[2]
        self.desty = move[3]
        # select the source
        
        buttonid = "but"+str(self.sourcex)+str(self.sourcey)     
        if whosemove == 'W':
            self.ids[buttonid].background_color = self.brightwhite
        else:
            self.ids[buttonid].background_color = self.darkblack
          
        Clock.schedule_once(self.cpu_select_dest, 1)  
            
       

    def cpu_select_dest(self,dt):
        buttonid = "but"+str(self.destx)+str(self.desty)     
        if self.whosemove == 'W':
            self.ids[buttonid].background_color = self.purewhite
        else:
            self.ids[buttonid].background_color = self.pureblack
        # schedule next part after a second 
        Clock.schedule_once(self.cpu_makethemove, 1)  
        
    def cpu_makethemove(self,dt):
        # check if the move is legal
        validmove = self.chessengine.checkifvalidmove(self.whosemove, self.sourcex, 
                                    self.sourcey, self.destx, self.desty)
        if validmove:  
            self.movestring = self.chessengine.getmovenotation(self.sourcex, self.sourcey, 
                            self.destx, self.desty) # get the move notation
            self.chessengine.makevalidmove(self.sourcex, self.sourcey, 
                            self.destx, self.desty)
                            
            # check for pawn promotion
            x,y = self.chessengine.checkforpawnpromotion(self.whosemove)
            if x != -1:
                self.promotex = x
                self.promotey = y
                self.promoteprawn(self.whosemove, 'Q')
            else:
                self.updatebothmessages(self.movestring,self.whosemove)
                if self.whosemove == 'B': # switch the players turn
                    self.whosemove = 'W'
                else:
                    self.whosemove = 'B'
                self.setwidgetbackgroundcolors()
                self.resetaftermove()
                if self.chessengine.checkifincheck(self.whosemove,self.chessengine.board):
                    self.setallfontsonecolor((0,0,1,1)) # turn the fonts blue if in check        
        else:
            self.resign()


       
        



    def buttonpress(self, x, y):
        """ Process a button press on the game board.  Each board square is a button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            return 
        self.cancelcount = 0
        if self.resetcount == 0:  # pressing the same square five times in a row
            self.resetcount = 1   # resets the game
            self.resetx = x
            self.resety = y
        elif self.resetx == x and self.resety == y:
            self.resetcount += 1
        else:
            self.resetcount = 0
     
        if self.resetcount == 5:
            del self.chessengine
            self.clock.cancel()
            self.initialsetup()   
            return
     
        if self.state == 'cpu turn to move':  # cpu is still thinking.  
            return
     
        if self.state == "looking for source":
            buttonid = "but"+str(x)+str(y)     
            self.sourcex = x
            self.sourcey = y
            if self.whosemove == 'W':
                self.ids[buttonid].background_color = self.brightwhite
            else:
                self.ids[buttonid].background_color = self.darkblack
            self.state = "looking for destination"
            return
            
        if self.state == "looking for destination":
            if x == self.sourcex and y == self.sourcey:
                return    # can't have source be same as destination
        
            # check if we need to erase the previous destination source
            if self.destx != -1:
                self.resetsquarebackground(self.destx,self.desty)
             
            buttonid = "but"+str(x)+str(y)     
            self.destx = x
            self.desty = y
            if self.whosemove == 'W':
                self.ids[buttonid].background_color = self.purewhite
            else:
                self.ids[buttonid].background_color = self.pureblack
            return     

    def movebuttonpress(self, color):
        """ Process a press on the move button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            self.numberplayers = 2
            self.blackplayer = 'human'
            self.whiteplayer = 'human'    
            self.initialsetup()
            return
        self.cancelcount = 0    
        self.resetcount = 0        
        if self.whosemove == color:
            if 'Promote' in self.state: # need to execute the pawn promotion.
                piece = self.state[8]
                if piece == 'K': piece = 'N'  # Knight not Night
                self.promoteprawn(self.whosemove,piece)
                return    
            if self.state == "looking for source": # need a destination
                return
            if self.state == "looking for destination" and self.destx != -1:
                # check if the move is legal
                validmove = self.chessengine.checkifvalidmove(self.whosemove, self.sourcex, 
                                    self.sourcey, self.destx, self.desty)
                if validmove:  
                    self.movestring = self.chessengine.getmovenotation(self.sourcex, self.sourcey, 
                                    self.destx, self.desty) # get the move notation
                    self.chessengine.makevalidmove(self.sourcex, self.sourcey, 
                                    self.destx, self.desty)
                    if not self.checkforpawnpromotion(self.whosemove):
                        self.updatebothmessages(self.movestring,self.whosemove)
                        if self.whosemove == 'B': # switch the players turn
                            self.whosemove = 'W'
                        else:
                            self.whosemove = 'B'
                        self.setwidgetbackgroundcolors()
                        self.resetaftermove()
                        if self.chessengine.checkifincheck(self.whosemove,self.chessengine.board):
                            self.setallfontsonecolor((0,0,1,1)) # turn the fonts blue if in check
                else:
                    self.increasemistakecount(self.whosemove)
                    self.resetaftermove()
                    self.setallfontsonecolor((1,0,0,1)) # turn the fonts red
                return
                
    def cancelbuttonpress(self, color):
        """ Process a press on the cancel button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            self.numberplayers = 1
            if color == 'B': 
                self.whiteplayer = 'cpu'
                self.blackplayer = 'human'
            else:
                self.whiteplayer = 'human'
                self.blackplayer = 'cpu'                 
            self.initialsetup()
            return
        self.cancelcount += 1
        self.resetcount = 0
        if self.cancelcount == 3:
            self.blind = 1-self.blind
            self.cancelcount = 0            
        if self.whosemove == color:            
            if 'Promote' in self.state: # rejected the pawn promotion piece
                     # need to cycle to the next one
                if self.state == 'Promote Queen?':
                    message = 'Promote Knight?'
                elif self.state == 'Promote Knight?':
                    message = 'Promote Rook?'
                elif self.state == 'Promote Rook?':
                    message = 'Promote Bishop?' 
                elif self.state == 'Promote Bishop?':
                    message = 'Promote Queen?'   
                self.updatemessage(message,color,color)
                self.state = message
                return    
            self.resetaftermove()
예제 #2
0
 def createchessengine(self):
     """ Creates the chess engine.  Maintains the game state and enforces move rules."""
     self.chessengine = ChessEngine() 
예제 #3
0
 def createchessengine(self):
     """ Creates the chess engine.  Maintains the game state and enforces move rules."""
     self.chessengine = ChessEngine()
예제 #4
0
class BlindChessRoot(BoxLayout):
    def initialsetup(self):  # called at the beginning of the game
        """ initialize the game state.  Called on the first button press."""
        self.createchessengine()
        self.purewhite = (1, 1, 1, 1)
        self.brightwhite = (0.9, 0.9, 0.9, 1)
        self.lightgray = (0.6, 0.6, 0.6, 1)
        self.darkgray = (0.4, 0.4, 0.4, 1)
        self.darkblack = (0.1, 0.1, 0.1, 1)
        self.pureblack = (0, 0, 0, 1)
        self.ids["messageW"].text = 'Your Move'
        self.ids["messageB"].text = 'Black Move'
        self.setcancelandmovebuttons('cancel', 'move')
        self.blind = 1  # 1 means blind.  0 means show the pieces
        self.sourcex = -1  # set the source and destination to none
        self.sourcey = -1
        self.destx = -1
        self.desty = -1
        self.resetbothmistakecounts()
        self.updateboardui()
        for x in range(0, 8):
            for y in range(0, 8):
                self.resetsquarebackground(x, y)
        self.whosemove = 'W'  # white moves first
        self.setwidgetbackgroundcolors()
        self.ids['clockW'].text = "10:00"
        self.ids['clockB'].text = "10:00"
        self.ids['messageW'].font_size = '30dp'
        self.ids['messageB'].font_size = '30dp'
        self.cancelcount = 0  # pressing cancel 3 times in a row toggles self.blind
        self.resetcount = 0  # pressing any board square 5 times in a row
        # resets the game
        self.resetx = 0
        self.resety = 0
        self.clock = Clock.schedule_interval(self.updateclocks, 1)
        if self.whiteplayer == 'human':
            self.state = "looking for source"
        else:
            self.state = "cpu turn to move"
            self.cpumove(0)

    def createchessengine(self):
        """ Creates the chess engine.  Maintains the game state and enforces move rules."""
        self.chessengine = ChessEngine()

    def updateboardui(self):
        """ Update the display to match the engine."""
        for x in range(0, 8):
            for y in range(0, 8):
                stringid = "but" + str(x) + str(y)
                colorpiece = self.chessengine.getpiece(x, y)
                buttonid = "but" + str(x) + str(y)
                if self.blind == 0 and colorpiece[0] != '0':
                    if colorpiece[0] == 'B':
                        self.ids[buttonid].color = self.pureblack
                    else:
                        self.ids[buttonid].color = self.purewhite
                    self.ids[buttonid].text = colorpiece[1]
                else:
                    self.ids[buttonid].text = ''

    def setallfontsonecolor(self, color):
        """ Sets the button and counts to a color to alert the player something has happened."""
        self.ids['clockW'].color = color
        self.ids['clockB'].color = color
        self.ids['mistakecountW'].color = color
        self.ids['mistakecountB'].color = color
        self.ids['moveW'].color = color
        self.ids['moveB'].color = color
        self.ids['cancelW'].color = color
        self.ids['cancelB'].color = color

    def restoreallfonts(self):
        """ Restores the button and counts to their original color."""
        almostblack = (0.2, 0.2, 0.2, 1)
        almostwhite = (0.8, 0.8, 0.8, 1)
        self.ids['clockW'].color = almostwhite
        self.ids['clockB'].color = almostblack
        self.ids['mistakecountW'].color = almostwhite
        self.ids['mistakecountB'].color = almostblack
        self.ids['moveW'].color = self.darkgray
        self.ids['moveB'].color = self.lightgray
        self.ids['cancelW'].color = self.darkgray
        self.ids['cancelB'].color = self.lightgray

    def getboardcolor(self, x, y):
        """ Returns the background color of a board square."""
        if (y % 2 == 0 and x % 2 == 0) or (y % 2 == 1 and x % 2 == 1):
            return self.darkgray
        else:
            return self.lightgray

    def updateclocks(self, dt):
        """ Adds one second to the active board clock."""
        if self.whosemove == 'W':
            timestring = self.ids['clockW'].text
        else:
            timestring = self.ids['clockB'].text

        if timestring != '00:00':
            if timestring[4] != '0':
                timestring = timestring[0:4] + str(int(timestring[4]) - 1)
            else:
                if timestring[3] != '0':
                    timestring = timestring[0:3] + str(int(timestring[3]) -
                                                       1) + '9'
                else:
                    if timestring[1] != '0':
                        timestring = timestring[0] + str(
                            int(timestring[1]) - 1) + timestring[2] + '59'
                    else:
                        timestring = str(int(timestring[0]) - 1) + '9:59'
        if self.whosemove == 'W':
            self.ids['clockW'].text = timestring
        else:
            self.ids['clockB'].text = timestring

    def setwidgetbackgroundcolors(self):
        """ Sets the background color of the move and cancel buttons."""
        if self.whosemove == 'W':
            blackcolor = self.darkgray
            whitecolor = self.brightwhite
        else:
            blackcolor = self.darkblack
            whitecolor = self.lightgray
        self.ids["moveB"].background_color = blackcolor
        self.ids["cancelB"].background_color = blackcolor
        self.ids["moveW"].background_color = whitecolor
        self.ids["cancelW"].background_color = whitecolor

    def resetsquarebackground(self, x, y):
        """ Resets a board square back to its original color."""
        buttonid = "but" + str(x) + str(y)
        self.ids[buttonid].background_color = self.getboardcolor(x, y)

    def setcancelandmovebuttons(self, canceltext, movetext):
        self.ids["moveB"].text = movetext
        self.ids["cancelB"].text = canceltext
        self.ids["moveW"].text = movetext
        self.ids["cancelW"].text = canceltext

    def resetbothmistakecounts(self):
        labelidblack = "mistakecountB"
        labelidwhite = "mistakecountW"
        self.ids[labelidblack].text = str(0)
        self.ids[labelidwhite].text = str(0)

    def increasemistakecount(self, color):
        """ Increment the mistake count of the active player."""
        # read the mistake count and convert to a number
        labelid = "mistakecount" + color
        mistakecount = int(self.ids[labelid].text)
        mistakecount += 1  # increment
        self.ids[labelid].text = str(
            mistakecount)  # convert to a string and update

    def updatebothmessages(self, message, colortodraw):
        """" Update the on screen message to both players."""
        colorvalue = self.purewhite
        if colortodraw == 'B': colorvalue = self.pureblack
        self.ids['messageW'].text = message
        self.ids['messageB'].text = message
        self.ids['messageW'].color = colorvalue
        self.ids['messageB'].color = colorvalue

    def updatemessage(self, message, colortoupdate, colortodraw):
        """ Update the on screen message of one of the players."""
        labelid = "message" + colortoupdate
        self.ids[labelid].text = message
        if colortodraw == 'W':
            self.ids[labelid].color = self.purewhite
        else:
            self.ids[labelid].color = self.pureblack

    def resetaftermove(self):
        """ Reset the board after a move."""
        # reset both the cursors ui
        if self.sourcex != -1:
            self.resetsquarebackground(self.sourcex, self.sourcey)
        if self.destx != -1:
            self.resetsquarebackground(self.destx, self.desty)
        # reset the source and destination
        self.sourcex = -1
        self.sourcey = -1
        self.destx = -1
        self.desty = -1
        # redraw the board
        self.updateboardui()
        # reset the message colors
        self.restoreallfonts()
        # set the state
        self.state = "looking for source"
        if ((self.whiteplayer == 'cpu' and self.whosemove == 'W')
                or (self.blackplayer == 'cpu' and self.whosemove == 'B')):
            self.state = "cpu turn to move"
            self.cpumove(0)

    def checkforpawnpromotion(self, color):
        """ Check if a pawn needs to be promoted and prompt the user if they want a queen."""
        # check if we need to do pawn promotion
        # we will start with Queen
        # The order we will present the promotion options is
        # Q, N, R, B,
        x, y = self.chessengine.checkforpawnpromotion(color)
        if x == -1: return False
        self.promotex = x  # save pawn promotion coordinates for later
        self.promotey = y
        # redraw the board
        self.updateboardui()
        self.updatemessage('Promote Queen?', color, color)
        self.state = "Promote Queen?"
        return True

    def promoteprawn(self, color, piece):
        """ Promote a pawn to the selected piece."""
        self.chessengine.promotepawn(color, piece, self.promotex,
                                     self.promotey)
        self.movestring += piece
        oppcolor = 'B'
        if color == 'B': oppcolor = 'W'
        if self.chessengine.checkifincheck(oppcolor, self.chessengine.board):
            self.movestring += '+'
        self.updatebothmessages(self.movestring, self.whosemove)
        if self.whosemove == 'B':  # switch the players turn
            self.whosemove = 'W'
        else:
            self.whosemove = 'B'
        self.setwidgetbackgroundcolors()
        self.resetaftermove()
        if self.chessengine.checkifincheck(self.whosemove,
                                           self.chessengine.board):
            self.setallfontsonecolor(
                (0, 0, 1, 1))  # turn the fonts blue if in check

    def resign(self):
        self.state = 'CPU resigns'
        if self.whosemove == 'B': message = "BLACK RESIGNS"
        else: message = "WHITE RESIGNS"
        self.updatebothmessages(
            message,
            self.whosemove)  # change the message to BLACK or WHITE RESIGNS
        self.setallfontsonecolor((0, 1, 0, 1))  # set the fonts to green

    def cpumove(self, dt):
        whosemove = self.whosemove
        move = self.chessengine.getcomputermoveincremental(whosemove)
        if move == 'RESIGN':
            self.resign()
            return  # user will need to reset the board to exit this state.
        if move == False:
            Clock.schedule_once(self.cpumove, 0.1)
            return

        self.sourcex = move[0]
        self.sourcey = move[1]
        self.destx = move[2]
        self.desty = move[3]
        # select the source

        buttonid = "but" + str(self.sourcex) + str(self.sourcey)
        if whosemove == 'W':
            self.ids[buttonid].background_color = self.brightwhite
        else:
            self.ids[buttonid].background_color = self.darkblack

        Clock.schedule_once(self.cpu_select_dest, 1)

    def cpu_select_dest(self, dt):
        buttonid = "but" + str(self.destx) + str(self.desty)
        if self.whosemove == 'W':
            self.ids[buttonid].background_color = self.purewhite
        else:
            self.ids[buttonid].background_color = self.pureblack
        # schedule next part after a second
        Clock.schedule_once(self.cpu_makethemove, 1)

    def cpu_makethemove(self, dt):
        # check if the move is legal
        validmove = self.chessengine.checkifvalidmove(self.whosemove,
                                                      self.sourcex,
                                                      self.sourcey, self.destx,
                                                      self.desty)
        if validmove:
            self.movestring = self.chessengine.getmovenotation(
                self.sourcex, self.sourcey, self.destx,
                self.desty)  # get the move notation
            self.chessengine.makevalidmove(self.sourcex, self.sourcey,
                                           self.destx, self.desty)

            # check for pawn promotion
            x, y = self.chessengine.checkforpawnpromotion(self.whosemove)
            if x != -1:
                self.promotex = x
                self.promotey = y
                self.promoteprawn(self.whosemove, 'Q')
            else:
                self.updatebothmessages(self.movestring, self.whosemove)
                if self.whosemove == 'B':  # switch the players turn
                    self.whosemove = 'W'
                else:
                    self.whosemove = 'B'
                self.setwidgetbackgroundcolors()
                self.resetaftermove()
                if self.chessengine.checkifincheck(self.whosemove,
                                                   self.chessengine.board):
                    self.setallfontsonecolor(
                        (0, 0, 1, 1))  # turn the fonts blue if in check
        else:
            self.resign()

    def buttonpress(self, x, y):
        """ Process a button press on the game board.  Each board square is a button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            return
        self.cancelcount = 0
        if self.resetcount == 0:  # pressing the same square five times in a row
            self.resetcount = 1  # resets the game
            self.resetx = x
            self.resety = y
        elif self.resetx == x and self.resety == y:
            self.resetcount += 1
        else:
            self.resetcount = 0

        if self.resetcount == 5:
            del self.chessengine
            self.clock.cancel()
            self.initialsetup()
            return

        if self.state == 'cpu turn to move':  # cpu is still thinking.
            return

        if self.state == "looking for source":
            buttonid = "but" + str(x) + str(y)
            self.sourcex = x
            self.sourcey = y
            if self.whosemove == 'W':
                self.ids[buttonid].background_color = self.brightwhite
            else:
                self.ids[buttonid].background_color = self.darkblack
            self.state = "looking for destination"
            return

        if self.state == "looking for destination":
            if x == self.sourcex and y == self.sourcey:
                return  # can't have source be same as destination

            # check if we need to erase the previous destination source
            if self.destx != -1:
                self.resetsquarebackground(self.destx, self.desty)

            buttonid = "but" + str(x) + str(y)
            self.destx = x
            self.desty = y
            if self.whosemove == 'W':
                self.ids[buttonid].background_color = self.purewhite
            else:
                self.ids[buttonid].background_color = self.pureblack
            return

    def movebuttonpress(self, color):
        """ Process a press on the move button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            self.numberplayers = 2
            self.blackplayer = 'human'
            self.whiteplayer = 'human'
            self.initialsetup()
            return
        self.cancelcount = 0
        self.resetcount = 0
        if self.whosemove == color:
            if 'Promote' in self.state:  # need to execute the pawn promotion.
                piece = self.state[8]
                if piece == 'K': piece = 'N'  # Knight not Night
                self.promoteprawn(self.whosemove, piece)
                return
            if self.state == "looking for source":  # need a destination
                return
            if self.state == "looking for destination" and self.destx != -1:
                # check if the move is legal
                validmove = self.chessengine.checkifvalidmove(
                    self.whosemove, self.sourcex, self.sourcey, self.destx,
                    self.desty)
                if validmove:
                    self.movestring = self.chessengine.getmovenotation(
                        self.sourcex, self.sourcey, self.destx,
                        self.desty)  # get the move notation
                    self.chessengine.makevalidmove(self.sourcex, self.sourcey,
                                                   self.destx, self.desty)
                    if not self.checkforpawnpromotion(self.whosemove):
                        self.updatebothmessages(self.movestring,
                                                self.whosemove)
                        if self.whosemove == 'B':  # switch the players turn
                            self.whosemove = 'W'
                        else:
                            self.whosemove = 'B'
                        self.setwidgetbackgroundcolors()
                        self.resetaftermove()
                        if self.chessengine.checkifincheck(
                                self.whosemove, self.chessengine.board):
                            self.setallfontsonecolor(
                                (0, 0, 1,
                                 1))  # turn the fonts blue if in check
                else:
                    self.increasemistakecount(self.whosemove)
                    self.resetaftermove()
                    self.setallfontsonecolor(
                        (1, 0, 0, 1))  # turn the fonts red
                return

    def cancelbuttonpress(self, color):
        """ Process a press on the cancel button."""
        message = self.ids["messageB"].text
        if message == 'Select Number of Players':
            self.numberplayers = 1
            if color == 'B':
                self.whiteplayer = 'cpu'
                self.blackplayer = 'human'
            else:
                self.whiteplayer = 'human'
                self.blackplayer = 'cpu'
            self.initialsetup()
            return
        self.cancelcount += 1
        self.resetcount = 0
        if self.cancelcount == 3:
            self.blind = 1 - self.blind
            self.cancelcount = 0
        if self.whosemove == color:
            if 'Promote' in self.state:  # rejected the pawn promotion piece
                # need to cycle to the next one
                if self.state == 'Promote Queen?':
                    message = 'Promote Knight?'
                elif self.state == 'Promote Knight?':
                    message = 'Promote Rook?'
                elif self.state == 'Promote Rook?':
                    message = 'Promote Bishop?'
                elif self.state == 'Promote Bishop?':
                    message = 'Promote Queen?'
                self.updatemessage(message, color, color)
                self.state = message
                return
            self.resetaftermove()
예제 #5
0
def main():
    p.init()
    screen = p.display.set_mode((WIDTH, HEIGHT))
    clock = p.time.Clock()
    screen.fill(p.Color('white'))
    gs = ChessEngine.GameState()
    validMoves = gs.getValidMoves()
    moveMade = False
    animate = False
    loadImages()
    running = True
    sqSelected = ()
    playerClicks = []
    gameOver = False
    playerOne = True  # if a human is playing white then this will be true
    playerTwo = True  # same as above but with black
    while running:
        humanTurn = (gs.whiteToMove and playerOne) or (not gs.whiteToMove
                                                       and playerTwo)
        for e in p.event.get():
            if e.type == p.QUIT:
                running = False
            # mouse handler
            elif e.type == p.MOUSEBUTTONDOWN:
                if not gameOver and humanTurn:
                    location = p.mouse.get_pos()
                    col = location[0] // SQ_SIZE
                    row = location[1] // SQ_SIZE
                    if sqSelected == (
                            row, col):  # user clicked twice on same square
                        sqSelected = ()
                        playerClicks = []
                    else:
                        sqSelected = (row, col)
                        playerClicks.append(sqSelected)
                    if len(playerClicks) == 2:  # after 2nd click
                        print(ChessAi.attackedSquaresBm(gs))
                        move = ChessEngine.Move(playerClicks[0],
                                                playerClicks[1], gs.board)
                        print(move.getChessNotation())
                        print(gs.moveSequence)
                        for i in range(len(validMoves)):
                            if move == validMoves[i]:
                                gs.makeMove(validMoves[i])
                                moveMade = True
                                animate = True
                                sqSelected = ()
                                playerClicks = []
                        if not moveMade:
                            playerClicks = [sqSelected]

            # keypress handlers
            elif e.type == p.KEYDOWN:
                if e.key == p.K_z:  # undo
                    gs.undoMove()
                    moveMade = True
                    animate = False
                    gameOver = False
                    if e.key == p.K_r:  # resign/reset board
                        gs = ChessEngine.GameState()
                        validMoves = gs.getValidMoves()
                        sqSelected = ()
                        playerClicks = []
                        moveMade = False
                        animate = False
                        gameOver = False

        # AI move finder
        if not gameOver and not humanTurn:
            AIMove = ChessAi.findBestMove(gs, validMoves)
            if AIMove is None:
                AIMove = ChessAi.findRandomMove(validMoves)
            gs.makeMove(AIMove)
            moveMade = True
            animate = True

        if moveMade:
            if animate:
                animateMove(gs.moveLog[-1], screen, gs.board, clock)
            validMoves = gs.getValidMoves()
            moveMade = False
            animate = False

        drawGameState(screen, gs, validMoves, sqSelected)

        if gs.checkmate:
            gameOver = True
            if gs.whiteToMove:
                drawText(screen, 'Black wins by checkmate')
            else:
                drawText(screen, 'White wins by checkmate')
        elif gs.stalemate:
            gameOver = True
            drawText(screen, 'Stalemate you fool')

        clock.tick(MAX_FPS)
        p.display.flip()