コード例 #1
0
class BoardTest(unittest.TestCase):
	def setUp(self):
		self.board = Board(8)
		self.board2 = Board(3)
		self.board3 = Board(4)
		
	def testBoardSize(self):
		self.assertEqual(8,self.board.getSize())
		self.assertEqual(3,self.board2.getSize())
		self.assertEqual(4,self.board3.getSize())
		
	def test_Remove_From_Board(self):
		self.board.removePiece(2,1)
		self.assertEqual(0,self.board.countAiPieces())
		self.board.removePiece(6,6)
		self.assertEqual(0,self.board.countPlayerPieces())
		
	def test_Add_To_Board(self):
		# board 1
		self.board.addPiece("AI",0,1,1)
		self.board.addPiece("Player",0,6,6)
		self.assertEqual(1,self.board.countPlayerPieces())
		self.assertEqual(1,self.board.countAiPieces())
		self.assertTrue(self.board.pieceAt(1, 1))
		self.assertTrue(self.board.pieceAt(6, 6))
		
		# board 2		
		self.board2.addPiece("test",0,1,1)
		self.board2.addPiece("AI",3,1,2)
		self.assertEqual(0,self.board2.countPlayerPieces())
		self.assertEqual(0,self.board2.countAiPieces())
		self.assertFalse(self.board2.pieceAt(1, 1))
		self.assertFalse(self.board2.pieceAt(1, 2))
		
		self.board2.addPiece("AI",1,2,1)
		self.assertEqual(0,self.board2.countPlayerPieces())
		self.assertEqual(1,self.board2.countAiPieces())
		self.assertTrue(self.board2.pieceAt(2, 1))
		
		# board 3
		self.board3.addPiece("AI",0,1,1)
		self.assertEqual(0,self.board3.countPlayerPieces())
		self.assertEqual(1,self.board3.countAiPieces())
		self.assertTrue(self.board3.pieceAt(1, 1))
	
	def test_Get_Piece_Info(self):
		# board 1
		self.piece = self.board.getPieceAt(6, 6)
		self.assertEqual("Player", self.piece.getOwner())
		self.assertEqual(1, self.piece.getType())
		
		# board 2
		self.piece = self.board2.getPieceAt(2, 1)
		self.assertEqual("AI", self.piece.getOwner())
		self.assertEqual(1, self.piece.getType())
		
		self.piece = self.board2.getPieceAt(1, 2)
		self.assertIsNone(self.piece)
		
		self.piece = self.board2.getPieceAt(1, 1)
		self.assertIsNone(self.piece)

		# board 3
		self.piece = self.board3.getPieceAt(1, 1)
		self.assertEqual("AI", self.piece.getOwner())
		self.assertEqual(0, self.piece.getType())
		
	def test_Move_Piece(self):
		self.assertTrue(self.board.pieceAt(1, 1))
		self.board.movePiece(1, 1, 2, 1)
		self.assertFalse(self.board.pieceAt(1, 1))
		self.assertTrue(self.board.pieceAt(2, 1))

		self.assertTrue(self.board2.pieceAt(2, 1))
		self.board2.movePiece(2, 1, 2, 2)
		self.assertFalse(self.board2.pieceAt(2, 1))
		self.assertTrue(self.board2.pieceAt(2, 2))

		self.assertTrue(self.board3.pieceAt(1, 1))
		self.board3.movePiece(1, 1, 2, 1)
		self.assertFalse(self.board3.pieceAt(1, 1))
		self.assertTrue(self.board3.pieceAt(2, 1))
	
	def test_Update_Piece(self):
		self.board.updatePieceType(1,6,6)
		self.piece = self.board.getPieceAt(6, 6)
		self.assertEqual("Player", self.piece.getOwner())
		self.assertEqual(1, self.piece.getType())
		
	def tearDown(self):
		self.board = None
		self.board2 = None
		self.board3 = None
	
	def main(self):
		self.setUp()
		self.testBoardSize()
		self.test_Add_To_Board()
		self.test_Update_Piece()
		self.test_Get_Piece_Info()
		self.test_Move_Piece()
		self.test_Remove_From_Board()
		self.tearDown()
コード例 #2
0
class Checkers:
    """
        default constructor creates the board and populates
        the board with pieces 
    """
    def __init__(self):
        self.board = Board(8)
        self.size = self.board.getSize()
        self.turn = 0
        self.best_move = None
        self.game_over = False
        self.jumpAgain = (False,None,None)
        
        for y in range(0,3):
            for x in range(self.size):
                if(y%2 ==0 and x%2 ==1 ):
                    self.board.addPiece("AI", 0, x, y)
                if(y%2==1 and x%2 ==0):
                    self.board.addPiece("AI", 0, x, y)
        
        for y in range(5,self.size):
            for x in range(self.size):
                if(y%2 ==0 and x%2 ==1 ):
                    self.board.addPiece("Player", 0, x, y)
                if(y%2==1 and x%2 ==0):
                    self.board.addPiece("Player", 0, x, y)
                    
    def loadBoard(self,board):
        self.board = board
        
    # returns the number of Ai pieces
    def getAI(self):
        return self.board.countAiPieces()
    
    # returns the number of player pieces
    def getPlayer(self):
        return self.board.countPlayerPieces()
    
    # ends the game
    def resign(self):
        self.game_over = True
        
    # returns piece at position X Y on the Board
    def getPiece(self,x,y):
        return self.board.getPieceAt(int(x),int (y))
    
    """
         gets if any of the players pieces can jump and adds it to
         the array, and returns it
    """
    def forceJump(self,player):
        moves = []
        for i in range (self.size):
            for j in range (self.size):
                tmp = self.board.getPieceAt(i, j)
                # checks if tmp is not none and player == the piece
                if tmp and player == tmp.getOwner() :
                    jumpF = self.canJump(i, j)
                    # if jumpF array is not empty append i , j and each value in the array
                    # for that piece
                    if jumpF :
                        for n in jumpF:
                            moves.append(n)
        return moves

    # prints the game.    
    def printGame(self):
        count = 0
        tmp = " |0|1|2|3|4|5|6|7|\n"
        for y in range (self.board.getSize()): 
            tmp += str(y) +"|"
            for x in range (self.board.getSize()):
                if(self.board.pieceAt(x, y)== True):
                    count+=1
                    pi = Piece()
                    pi =self.board.getPieceAt(x, y)
                    if(pi.getOwner() == "AI"):
                        tmp = tmp + "0|"
                    else:
                        tmp = tmp + "X|"
                else:
                    tmp = tmp + " |"
            tmp += "\n" 
        print (str(tmp))
        
    # returns if the game is over    
    def isOver(self):
        return self.game_over
    
    # checks to see if the game has ended and sets game_over to true
    def checkWin(self):
        if self.board.countPlayerPieces ==0 or len(self.getMoves("Player")) == 0:
            self.game_over = True
            return "AI"
        elif self.board.countAiPieces ==0 or len(self.getMoves("AI")) == 0: 
            self.game_over = True
            return "Player"
    
    """ 
        validates if piece at X,Y can move to x1 , y1
        checks if x1 and y1 is inside the board and x1 and y1 is a empty space
        returns true or false
    """
    def validMove(self,x1,y1):
        if x1 < self.board.getSize() and x1>= 0 and y1 >= 0 and y1 < self.board.getSize():
            if not self.board.pieceAt(x1, y1):
                return True
        else:
            return False

    # moves a piece players piece from X Y to x1 y1
    def movePiece(self,player,x,y,x1,y1):
        
        moved = False
        #gets an array of movable positions x y given by user
        moves = self.getMoves(player)
        # move is the string of x y, x1 y1 for comparing to the array of movable positions
        move = str(x)+","+str(y)+","+str(x1)+","+str(y1)
        if not self.isOver() :
            if self.forceJump(player):
                #Second jump
                if self.jumpAgain[0]:
                    # if jumpagain is true get the jumpable moves for jumpAgain[1], jumpAgain[2]
                    moves = self.canJump(self.jumpAgain[1], self.jumpAgain[2])
                    
                    #compares moves to move if equal move the piece and remove the piece being jumped 
                    for i in moves:
                        if i == move:
                            self.board.movePiece(x, y, x1, y1)
                            # checks if a jump is true then remove the piece being jumped        
                            removePieceX = (x + (x1))/2
                            removePieceY = (y + (y1))/2
                            self.board.removePiece(removePieceX, removePieceY)
                            
                            #checks if it is king
                            if self.isKing(x1,y1):
                                self.board.updatePieceType(1,x1,y1)
                            
                            #checks if it can jump again sets jumpAgain to true if true else set to False
                            if self.canJump(x1, y1):
                                moved = False
                                self.jumpAgain=(True,x1,y1)
                                break
                            else:  
                                self.jumpAgain=(False,None,None)
                                moved = True
                                break    
                
                else:
                    # This is the first jump
                    for i in moves:
                        if i == move :
                            self.board.movePiece(x, y, x1, y1)
                            # checks if a jump is true then remove the piece being jumped        
                            removePieceX = (x + (x1))/2
                            removePieceY = (y + (y1))/2
                            self.board.removePiece(removePieceX, removePieceY)
                            #after jumping check if it can be Kinged and can it jump again 
                            if self.isKing(x1,y1):
                                self.board.updatePieceType(1,x1,y1)
                            
                            if self.canJump(x1, y1):
                                moved = False
                                self.jumpAgain= (True,x1,y1)
                                break
                            else:  
                                self.jumpAgain= (False,None,None)
                                moved = True
                                break
            else:
            # checks if the input equals any possible moves
                if moves:
                    for i in moves:
                        if(i == move):
                            self.board.movePiece(x, y, x1, y1)
                            self.jumpAgain=(False,None,None)
                            moved = True
                            break
                    # if it can be kinged and updates the piece to a king
                    if self.isKing(x1,y1):
                        self.board.updatePieceType(1,x1,y1)
                        
            #check is the game is over
            self.checkWin()
            
        return moved
        
    #ends the players turn
    def turnEnd(self):
        self.turn+=1  
    
    def AI(self):
        moveFinished= False
        # if turn is AI s
        if self.getTurn() == "AI":
            
            # using the alpha beta function to get the best possible score
            score = self.alpha_beta(self,"AI", 0,-10000,10000)
            
            while self.getTurn() == "AI" and  not self.isOver():
                # alpha_beta function assigns best_move
                movstr = self.best_move
                if score == -10000 or len(self.getMoves("AI")) == 0:
                    # if score == -10000  or length of moves for AI is 0 then no moves for available
                    # game over then 
                    self.game_over = True
                # parses movstr to move the piece
                x1 = movstr[0]
                y1 = movstr[1]
                x2 = movstr[2]
                y2 = movstr[3]
                moveFinished = self.movePiece("AI",x1, y1, x2, y2)   
                # checks if that piece can jump again
                movs = self.canJump(x2, y2)
                # if can jump again call alpha beta again to get the next best possibe move 
                # loop starts again
                if movs and not moveFinished: 
                    score = self.alpha_beta(self,"AI", 0,-10000,10000)
                # piece can't jump again and has moved end turn breaks the while looks
                else:
                    self.turnEnd()
        # returns a tuple for GUI to highlight the piece moved 
        if moveFinished  :
            return ((x1),(y1),(x2),(y2))  
        
    # returns if its players turn or AI's turn
    def getTurn(self):
        if(self.turn % 2 == 0):
            return "Player"
        else:
            return "AI"
    """
        checks if a piece can be Kinged when AI piece hits bottom of board 
         or Player piece hits the top of the board
    """
    def isKing(self,x,y):
        self.p = Piece()
        self.p = self.board.getPieceAt(x, y)
        if(self.board.pieceAt(x, y)):
            if self.p.getOwner() == "AI" and y == self.board.getSize()-1:
                return True
            elif self.p.getOwner() == "Player" and y == 0 :
                return True
            else:
                return False
        else:
            return False
    """
        returns the moves for the piece at x y if it can jump 
    """
    def canJump(self,x,y):
        moves = []
        tmp = self.board.getPieceAt(x, y)
        if tmp:
            start = 0
            finish = 0
            if tmp.getType() == 0:
                if tmp.getOwner() == "Player":
                    start = -1
                    finish = 0
        
                if tmp.getOwner() == "AI":
                    start = 1
                    finish = 2
                # Ai  # +1,-1 #-1 -1  player # +1 +1#-1 +1
                for i in range(-1,2):
                    for j in range (start,finish):
                        if (x +i < self.board.getSize() and x+i >=0) and (y+j <self.board.getSize() and y+j >=0):
                            tmp1 = self.board.getPieceAt(x+i, y+j)
                            if tmp1:
                                if tmp.getOwner() != tmp1.getOwner() :
                                    if self.validMove(x+i+i, y+j+j):
                                        moves.append(str(x)+","+str(y) +","+str(x+i+i)+","+str(y+j+j))

            #if piece is king then will try get all directions
            if tmp.getType() == 1:
                for i in range(-1,2):
                    for j in range (-1,2):
                        if (x +i < self.board.getSize() and x+i >=0) and (y+j <self.board.getSize() and y+j >=0):
                            tmp1 = self.board.getPieceAt(x+i, y+j)
                            if tmp1:
                                if tmp.getOwner() != tmp1.getOwner() :
                                    if self.validMove(x+i+i, y+j+j):
                                        moves.append(str(x)+","+str(y) +","+str(x+i+i)+","+str(y+j+j))
            
        return moves
    """
        returns the moves for the piece at x y if it can move
    """
    def pieceMovable(self,x,y):
        moves = []
        tmp = self.board.getPieceAt(x,y)
        if tmp :
            # if tmp is a king then check up left, up right, down left , down right
            if tmp.getType() == 1:
                if self.validMove(x-1, y-1):
                    moves.append(str(x-1)+","+str(y-1))
    
                if self.validMove(x+1, y-1):
                    moves.append(str(x+1)+","+str(y-1))
                    
                if self.validMove(x-1, y+1):
                    moves.append(str(x-1)+","+str(y+1))
    
                if self.validMove(x+1, y+1):
                    moves.append(str(x+1)+","+str(y+1))
            # Players pieces which will always be at the bottom              
            elif tmp.getOwner() == "Player" and tmp.getType() == 0:
                    
                # UP and left 
                if self.validMove(x-1, y-1):
                    moves.append(str(x-1)+","+str(y-1))
                # Up and right 
                if self.validMove(x+1, y-1):
                    moves.append(str(x+1)+","+str(y-1))
    
            # AI pieces which will always be at the Top        
            elif tmp.getOwner() == "AI" and tmp.getType() == 0:
    
                #down and right   
                if self.validMove(x+1, y+1):
                        moves.append(str(x+1)+","+str(y+1))
                #down and left
                if self.validMove(x-1, y+1):
                    moves.append(str(x-1)+","+str(y+1))            
    
        return moves
        
    # gets all the moves available to the player
    def getMoves(self,player):
        
        movableP = []
        # if it can jump again just get the moves that piece can jump again.
        if self.jumpAgain[0]:
            movableP = self.canJump(self.jumpAgain[1], self.jumpAgain[2])
        #check if any pieces can jump and just return the list of jumpable pieces and nothing else.
        else: 
            movableP = self.forceJump(player)
                                    
        # if there is no pieces that can jump for the player return the movable pieces
        if not movableP:

            for i in range (self.board.getSize()):
                for j in range (self.board.getSize()):
                    tmp = self.board.getPieceAt(i,j)
                    if tmp and tmp.getOwner() == player:
                            tmpMoves =self.pieceMovable(i, j)
                            if tmpMoves:
                                for p in range (len(tmpMoves)):
                                    movableP.append(str(i)+","+str(j)+","+str(tmpMoves[p]))
        return movableP
    
    # evaluates the player for minimax with alpha beta pruning 
    def evaluate(self,playerTurn):
        player = 0
        ai = 0
        for i in range (0,self.board.getSize()):
            for j in range (0,self.board.getSize()):
                tmp = self.board.getPieceAt(i, j)
                if tmp:
                    if tmp.getOwner() == "Player":
                            
                        if tmp.getType() == 0:
                            player += 5 
                            # Player piece at the left, top or right edge +2 as its a space position
                            if i == 0 or i == self.board.getSize()-1 or j==0 :
                                player+=2
                               
                        if tmp.getType() == 1:
                            player += 10
                            # stopping king moving between edge and the next empty space repeatedly
                            if i == 0 or i == self.board.getSize()-1 or j == 0 or j == self.board.getSize()-1:
                                player-=10
                   
                    if tmp.getOwner() == "AI":
                            
                        if tmp.getType() == 0:
                            ai += 5
                            # AI if piece at the left, bottom or right edge +2 as its a space position
                            if i == 0 or i == self.board.getSize()-1 or j == self.board.getSize()-1:
                                ai+=2
                            
                        if tmp.getType() == 1: 
                            ai += 10
                            # stopping king moving between edge and the next empty space repeatedly
                            if i == 0 or i == self.board.getSize()-1 or j == 0 or j == self.board.getSize()-1:
                                ai-=10
        # returns in favour of the playersTurn for minimax 
        if playerTurn == "AI":
            return player - ai
        else:
            return ai - player

    """
        minimax with alpha beta pruning
    """            
    def alpha_beta(self, board,player, ply, alpha, beta):
        QCoreApplication.processEvents()
        # amount of moves to look ahead currently 3 moves ahead
        
        ply_depth = 3
        # check for end state.
        board.checkWin()
        if ply >= ply_depth or  board.isOver(): 
            # return evaluation of board  if we reached final ply or end state
            score = board.evaluate(player) 
            return score
        #gets moves for the player.
        moves = board.getMoves(player)
        # Max's Turn
        if player == "AI"and not ply == ply_depth: # if AI to play on node
            # ply%2 is 0 every second turn
            # For each child of the root node.
            for i in moves:
                # create a deep copy of the board "Assignment statements in Python do not copy objects"
                # or else it is just a reference
                new_board = deepcopy(board)
                #parsing the value of i, moves
                x1 = int(i[0])
                y1 = int(i[2])
                x2 = int(i[4])
                y2 = int(i[6])
                #moving the piece
                finishMove =new_board.movePiece("AI",x1,y1,x2,y2)
                
                if finishMove:
                    #if move is true then next player and ply +1
                    if player == 'AI': 
                        player = 'Player'
                    # score = alpha-beta(next players turn,child,alpha,beta) 
                    score = self.alpha_beta(new_board,player, ply+1, alpha, beta)
                else:
                    # else its still that players turn possibly more then one jump can happen.
                    player ="AI"
                    score = self.alpha_beta(new_board,player, ply, alpha, beta)
                    
                # if score > alpha then alpha = score found a better move
                if score > alpha:
                    if ply == 0: 
                        self.best_move = (x1,y1, x2, y2) # save the move best move
                    #assign the better score to alpha
                    alpha = score
                # if alpha >= beta then return alpha (cut off) 
                if alpha >= beta:
                    return alpha
    
            #return alpha this is our best score
            return alpha
    
        # Mins turn
        elif player == "Player" and not ply == ply_depth: # the opponent of the AI to play on this node
            # ply%2 is 1 every second turn
            # For each child 
            for i in moves:
                # create a deep copy of the board "Assignment statements in Python do not copy objects"
                # or else it is just a reference
                new_board = deepcopy(board)
                #parsing the value of i, moves
                x1 = int(i[0])
                y1 = int(i[2])
                x2 = int(i[4])
                y2 = int(i[6])
                #moving the piece
                finishMove =new_board.movePiece("Player",x1,y1,x2,y2)
                if finishMove:
                    #if move is true then next player and ply +1
                    if player == 'Player': 
                        player = 'AI'
                    # score = alpha-beta(next players turn,child,alpha,beta) 
                    score = self.alpha_beta( new_board, player,ply+1, alpha, beta)
                else: 
                    # else its still that players turn possibly more then one jump can happen.
                    player = 'Player'
                    score = self.alpha_beta( new_board, player,ply, alpha, beta)
                    
                # if score < beta then beta = score, opponent found a better, worse move
                if score < beta: 
                    beta = score
                # if alpha >= beta then return beta (cut off) 
                if alpha >= beta: 
                    return beta
            # return beta the opponent's best move 
            return beta