def blockTrap(originalBoard, myMove, opponentMove, futureBoard, playerTurn): numrows, numcolumns= py.shape(originalBoard) opponentTurn= getOpponent( playerTurn ) interBoard= py.copy( originalBoard ) interBoard[myMove]= playerTurn winningChains= glf.getSequentialCellsPlus( interBoard, 4 ) #print "winning Chains: " ,winningChains opWins= winningChains[opponentTurn] numOpWins= len( opWins ) fwinningChains= glf.getSequentialCellsPlus( futureBoard, 4 ) fopWins= fwinningChains[opponentTurn] #print "fopWins: ", fopWins fnumOpWins= len( fopWins ) if fnumOpWins >= numOpWins + 2: #then there was a trap. #get entries in fwinningChains that are new (i.e not in winningChains) newOpPossibleWins= [] for pair in fopWins: #print "pair is: ", pair posOfPair, directOfPair= pair absent= True for pos,direct in opWins: if directOfPair == direct and posOfPair.tolist() == pos.tolist(): absent= False if absent: newOpPossibleWins.append(pair) #check that there are only 2 new possibilities #assert len(newOpPossibleWins) == 2 #go through the first 4 for posWin in newOpPossibleWins: pos,direct= posWin rowdirect,columndirect= direct for row in pos: x,y= row[0], row[1] adjRow= x+rowdirect adjCol= y+columndirect if adjRow < 6 and adjRow > 0 and adjCol < 7 and adjCol > 0 and isPlayable( (x,y), originalBoard ) and originalBoard[adjRow,adjCol] == opponentTurn: return 1, (x,y) return -1, myMove '''#check if opponentMove is playable from originalBoard if isPlayable( opponentMove, originalBoard ): return 1, opponentMove else: #must have been made playable by myMove return -1, myMove''' else: #appears to be no trap return 0, myMove
def randomMovePlusPlus(gameBoard, playerTurn): move= None sequentialCells= glf.getSequentialCellsPlus(gameBoard,4) if playerTurn == 1: possibleWins= sequentialCells[1] possibleLosses= sequentialCells[2] elif playerTurn == 2: possibleWins= sequentialCells[2] possibleLosses= sequentialCells[1] #print "TRY TO WIN" for pos, direction in possibleWins: move= aif.blockOrWin(gameBoard, pos) if move: #print "WOOOOOOOONNN, playing: ", move break if not move: #print "TRY TO BLOCK OPPONENT" for pos, direction in possibleLosses: move= aif.blockOrWin(gameBoard, pos) if move: #print "BLOCKING OPPONENT, playing: " , move break if not move: #print "COULD NOT BLOCK OR WIN, playing random" return randomMove(gameBoard),1 else: return move,0
def lookAheadOnePlus(gameBoard, playerTurn): #get all possible moves on gameBoard possibleMoves= aif.getValidMoves(gameBoard) #get best move based on state of resulting boards bestMove, isBlockOrWin= bestLocalMovePlus(gameBoard, playerTurn) x,y= bestMove #score board for this player and opponent myOrScores, yourOrScores, orCandidateSlots= aif.scoreBoard(gameBoard, playerTurn) if not aif.isSafeToPlay((x,y), yourOrScores, gameBoard): #CAN USE THIS TO PREVENT CONNECT FOUR TRAPS #print "BEST MOVE IS A LOSS?!?!?!" pass if isBlockOrWin: #there cannot be a better play than a block or a win #print "FOUND IS BLOCK OR WIN FROM BESTLOCALMOVEPLUS" return bestMove, isBlockOrWin #find the best play that is neither a block or a win bestBoard= py.copy(gameBoard) bestBoard[bestMove]= playerTurn #py.zeros(py.shape(gameBoard)) opponentTurn= aif.getOpponent(playerTurn) for x,y in possibleMoves: #play move newBoard= py.copy(gameBoard) newBoard[x,y]= playerTurn oldSequentialCells= glf.getSequentialCellsPlus( bestBoard, 3 ) oldWinOpportunities= oldSequentialCells[playerTurn] oldLoseOpportunities= oldSequentialCells[opponentTurn] newSequentialCells= glf.getSequentialCellsPlus( newBoard, 3 ) newWinOpportunities= newSequentialCells[playerTurn] newLoseOpportunities= newSequentialCells[opponentTurn] myScores, yourScores, candidateSlots= aif.scoreBoard(newBoard, playerTurn) if aif.isSafeToPlay((x,y), yourOrScores, gameBoard) and len(newLoseOpportunities) < len(oldLoseOpportunities): #print "FOUND SOMETHING BETTER THAN BESTLOCALMOVEPLUS: ", x,y bestMove= (x,y) bestBoard= newBoard #return move leading to that state return bestMove, isBlockOrWin
def blockTrapFirst(originalBoard, myMove, opponentMove, futureBoard, playerTurn): opponentTurn= getOpponent( playerTurn ) interBoard= py.copy( originalBoard ) interBoard[myMove]= playerTurn winningChains= glf.getSequentialCellsPlus( interBoard, 4 ) opWins= winningChains[opponentTurn] numOpWins= len( opWins ) fwinningChains= glf.getSequentialCellsPlus( futureBoard, 4 ) fopWins= fwinningChains[opponentTurn] fnumOpWins= len( fopWins ) if fnumOpWins >= numOpWins + 2: #then there was a trap. #check if opponentMove is playable from originalBoard if isPlayable( opponentMove, originalBoard ): return 1, opponentMove else: #must have been made playable by myMove return -1, myMove else: #appears to be no trap return 0, myMove
def evalB( gameBoard, playerTurn ): opponentTurn= getOpponent( playerTurn ) #get whether board contains win or loss (or both) allWins= glf.getSequentialCellsNoV( gameBoard, 4 ) wins= len( allWins[playerTurn] ) losses= len( allWins[opponentTurn] ) #get results of scoreBoard myScores, yourScores, candidateSlots= scoreBoard( gameBoard, playerTurn ) times= 2 tempPt= 0.0 tempOt= 0.0 for score in sorted(candidateSlots.keys(), reverse=True): if times == 0: break nextBests= candidateSlots[score] for x,y,player in nextBests: if player == playerTurn: #update partial score tempPt+= score else: tempOt+= score times-=1 #get the number of offensive plays offPlays= 0.0 validMoves= getValidMoves( gameBoard ) filterWorked, validMoves= uselessSlotFilter( gameBoard, validMoves, playerTurn ) if filterWorked: offPlays= len(validMoves) #get the number of win/lose opportunities sequentialCells= glf.getSequentialCellsPlus( gameBoard, 4 ) winOpportunities= sequentialCells[playerTurn] loseOpportunities= sequentialCells[opponentTurn] numWins= len(winOpportunities) numLosses= len(loseOpportunities) #calculate linear combination #value= wins * 10000 + losses * (-10000) + tempPt * 0.3 + tempOt * (-0.1) + offPlays * 0.4 + numWins * 0.3 + numLosses * (-0.3) #value= wins * 10000 + losses * (-10000) + offPlays * 0.4 + numWins * 0.6 + tempPt * 0.1 + numLosses * (-0.1) + + tempOt * (-0.1) value= wins * 10000 + losses * (-10000) + offPlays * 0.4 + tempPt * 0.1 + numWins * 0.1 + numLosses * (-0.05) + tempOt * (-0.05) #print "value is ", value return value
def scoreTreeWithSeqCellsPlus( self, playerTurn ): #print "start scoring tree" opponent= getOpponent( playerTurn ) for boardNode in self.leafNodes: #print "start sequentialCellsPlus" sequentialCells= glf.getSequentialCellsPlus( boardNode.board, 4 ) #print "end sequentialCellsPlus" myCells= sequentialCells[playerTurn] oppCells= sequentialCells[ opponent ] #print "start boardContainswinner" winnerFound, winnerPlayerID, _, _= glf.boardContainsWinner( boardNode.board, 4 ) #print "end boardContainsWinner" if winnerFound and winnerPlayerID == opponent: score= len(myCells) - len(oppCells) - 1000.0 elif winnerFound and winnerPlayerID == playerTurn: score= len(myCells) - len(oppCells) + 100.0 else: score= len(myCells) - len(oppCells) boardNode.value= score #print "done scoring leaves" #recurse up the tree children= self.leafNodes parents= self.getPriorGen( children ) while parents != [None]: for parentNode in parents: childrenOfParent= self.structure[parentNode] player= childrenOfParent[0].playerTurn childrenValues= [] for child in childrenOfParent: childrenValues.append( child.value ) if player == playerTurn: #get maximum parentNode.value= max( childrenValues ) else: #get minimum parentNode.value= min( childrenValues ) children= parents parents= self.getPriorGen( children )
def scoreBoard(gameBoard, playerTurn): #2 black copies of board myScores= (gameBoard != 0) * (-1) #myCandidateSlots= dict() yourScores= (gameBoard != 0) * (-1) #yourCandidateSlots= dict() candidateSlots= dict() #for seq=2:4 sequentialPositions= 2 limit= 5 for sequentialPos in range(sequentialPositions,limit): sequentialCells= glf.getSequentialCellsPlus(gameBoard, sequentialPos) #print "CELLS ARE: ", sequentialCells myCells= sequentialCells[playerTurn] #print "MY CELLS ARE: ", myCells yourCells= sequentialCells[1] if playerTurn == 2 else sequentialCells[2] for sequence in myCells: #add sequentialPos to slot == 0 #print "sequence is : ", sequence pos,direction= sequence #print "pos is: ", pos for row in pos: #print "row is: ", row r,c= row[0], row[1] #print "r,c are: ", r, c if gameBoard[r,c] == 0: oldscore= myScores[r,c] myScores[r,c]+= sequentialPos #print "Adding ", r,c ,"to index ", myScores[r,c] #print "Removeing ", r,c , "from index ", oldscore try: candidateSlots[myScores[r,c]]+= [(r,c,playerTurn)] except KeyError: candidateSlots[myScores[r,c]]= [(r,c,playerTurn)] if oldscore != 0: try: candidateSlots[oldscore].remove((r,c,playerTurn)) except KeyError: candidateSlots[oldscore]=[] '''try: myCandidateSlots[(r,c)]+= sequentialPos except KeyError: myCandidateSlots[(r,c)]= sequentialPos''' for sequence in yourCells: pos,direction= sequence for row in pos: r,c= row[0], row[1] if gameBoard[r,c] == 0: oldscore= yourScores[r,c] yourScores[r,c]+= sequentialPos opponentTurn= 1 if playerTurn == 2 else 2 try: candidateSlots[yourScores[r,c]]+= [(r,c,opponentTurn)] except KeyError: candidateSlots[yourScores[r,c]]= [(r,c,opponentTurn)] if oldscore != 0: try: candidateSlots[oldscore].remove((r,c,opponentTurn)) except KeyError: candidateSlots[oldscore]=[] '''try: yourCandidateSlots[(r,c)]+= sequentialPos except KeyError: yourCandidateSlots[(r,c)]= sequentialPos''' return myScores, yourScores, candidateSlots
def lookAheadThricePlus(gameBoard, playerTurn): #get all possible moves on gameBoard possibleMoves= aif.getValidMoves(gameBoard) #get best move based on state of resulting boards bestMove, isBlockOrWin= lookAheadTwicePlus(gameBoard, playerTurn) x,y= bestMove #score board for this player and opponent myOrScores, yourOrScores, orCandidateSlots= aif.scoreBoard(gameBoard, playerTurn) if not aif.isSafeToPlay((x,y), yourOrScores, gameBoard): #print "lookAheadThricePlus: -- BEST MOVE IS A LOSS?!?!?!" pass if isBlockOrWin: #there cannot be a better play than a block or a win #print "lookAheadThricePlus: --- FOUND IS BLOCK OR WIN FROM BESTLOCALMOVEPLUS" return bestMove, isBlockOrWin elif isBlockOrWin == 2: return bestMove, 2 bestBoard= py.copy(gameBoard) bestBoard[bestMove]= playerTurn #py.zeros(py.shape(gameBoard)) trapFlag= 0 slot= (-1,-1) opponentTurn= aif.getOpponent(playerTurn) opponentPossibleMoves= aif.getValidMoves(bestBoard) for x,y in opponentPossibleMoves: temp= py.copy(bestBoard) temp[x,y]= opponentTurn t, s= aif.preventTrapPlus(gameBoard,bestMove, (x,y), temp, playerTurn) if t == 1: #print " PREVENTING TRAAAAAAAAAP IN DEFAULT LOOKAHEADTHRICEPLUS ----------------------------" return s, 2 elif t == -1: trapFlag= t slot= s break elif t == 0: pass #get best move for opponent yourBestMove, _= lookAheadTwicePlus(bestBoard, opponentTurn) bestBoard[yourBestMove]= opponentTurn myOtherBestMove, _= lookAheadTwicePlus(bestBoard, playerTurn) bestBoard[myOtherBestMove]= playerTurn #find the best play that is neither a block or a win for x,y in possibleMoves: if (x,y) == slot: #print "AVOIDING AVOINDING AVOIDING AVOIDING AVOIDING" pass else: #play move newBoard= py.copy(gameBoard) newBoard[x,y]= playerTurn newBoardAfterMyFirstTurn= py.copy(newBoard) #get opponent move opponentMove, _= lookAheadTwicePlus(gameBoard, opponentTurn) newBoard[opponentMove]= opponentTurn flag2,slot2= aif.preventTrapPlus(gameBoard, (x,y), opponentMove, newBoard, playerTurn) if trapFlag == -1 and flag2 != -1 and aif.isSafeToPlayPlus( (x,y), playerTurn, gameBoard ): #print "ThricePlus: REPLACING BAD BEST MOVE ", bestMove, " LEADING TO TRAP WITH ", x,y bestMove= (x,y) bestBoard= newBoard trapFlag= 0 #get my next best move based on this new state #TODO if final state has trap or is loss, discard this original move completely. If not, move on to compare this state to the best state seen. #TODO check if no traps for opponent but trap for self, then play there myMove, _= lookAheadTwicePlus(newBoard, playerTurn) newBoard[myMove]= playerTurn flag3,slot3= aif.preventTrapPlus(newBoardAfterMyFirstTurn, opponentMove, myMove, newBoard, opponentTurn) if flag3 == 1 and aif.isSafeToPlayPlus( slot3, playerTurn, gameBoard ): #Trap already active in our favor, use it! return slot3, 1 if flag3 == -1 and aif.isSafeToPlayPlus( slot3, playerTurn, gameBoard ): #opponent made a move that activated the trap: consider our move that led to it as a valid place to play pass if flag2== -1: pass else: oldSequentialCells= glf.getSequentialCellsPlus( bestBoard, 4 ) oldWinOpportunities= oldSequentialCells[playerTurn] oldLoseOpportunities= oldSequentialCells[opponentTurn] newSequentialCells= glf.getSequentialCellsPlus( newBoard, 4 ) newWinOpportunities= newSequentialCells[playerTurn] newLoseOpportunities= newSequentialCells[opponentTurn] myScores, yourScores, candidateSlots= aif.scoreBoard(newBoard, playerTurn) if aif.isSafeToPlay((x,y), yourOrScores, gameBoard) and len(newLoseOpportunities) < len(oldLoseOpportunities): bestMove= (x,y) bestBoard= newBoard #return move leading to that state if trapFlag == -1 and bestMove == slot: #print "OOOOOOOOOOOOH NOOOOooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo DON'T PLAY THERE" pass return bestMove, isBlockOrWin
def lookAheadTwicePlus(gameBoard, playerTurn): #get all possible moves on gameBoard possibleMoves= aif.getValidMoves(gameBoard) #get best move based on state of resulting boards bestMove, isBlockOrWin= lookAheadOnePlus(gameBoard, playerTurn) x,y= bestMove #score board for this player and opponent myOrScores, yourOrScores, orCandidateSlots= aif.scoreBoard(gameBoard, playerTurn) if not aif.isSafeToPlay((x,y), yourOrScores, gameBoard): #print "lookAheadTwicePlus: -- BEST MOVE IS A LOSS?!?!?!" pass if isBlockOrWin: #there cannot be a better play than a block or a win return bestMove, isBlockOrWin bestBoard= py.copy(gameBoard) bestBoard[bestMove]= playerTurn trapFlag= 0 slot= (-1,-1) opponentTurn= aif.getOpponent(playerTurn) opponentPossibleMoves= aif.getValidMoves(bestBoard) for x,y in opponentPossibleMoves: temp= py.copy(bestBoard) temp[x,y]= opponentTurn t, s= aif.blockTrap(gameBoard,bestMove, (x,y), temp, playerTurn) if t == 1 and aif.isSafeToPlayPlus( s, playerTurn, gameBoard ): #print " PREVENTING TRAAAAAAAAAP IN DEFAULT LOOKAHEADTWICEPLUS ----------------------------" return s, 2 elif t == -1: trapFlag= t slot= s break elif t == 0: pass #get best move for opponent yourBestMove, _= lookAheadOnePlus(bestBoard, opponentTurn) bestBoard[yourBestMove]= opponentTurn #find the best play that is neither a block or a win for x,y in possibleMoves: if trapFlag == -1 and (x,y) == slot: #print "AVOIDING AVOINDING AVOIDING AVOIDING AVOIDING" pass else: #play move newBoard= py.copy(gameBoard) newBoard[x,y]= playerTurn #get opponent move opponentMove, _= lookAheadOnePlus(gameBoard, opponentTurn) newBoard[opponentMove]= opponentTurn if trapFlag == -1 and bestMove == slot and (x,y) != slot and aif.isSafeToPlayPlus( (x,y), playerTurn, gameBoard ): #print "REPLACING BAD BEST MOVE ", bestMove, " LEADING TO TRAP WITH ", x,y bestMove= (x,y) bestBoard= newBoard trapFlag= 0 oldSequentialCells= glf.getSequentialCellsPlus( bestBoard, 3 ) oldWinOpportunities= oldSequentialCells[playerTurn] oldLoseOpportunities= oldSequentialCells[opponentTurn] newSequentialCells= glf.getSequentialCellsPlus( newBoard, 3 ) newWinOpportunities= newSequentialCells[playerTurn] newLoseOpportunities= newSequentialCells[opponentTurn] myScores, yourScores, candidateSlots= aif.scoreBoard(newBoard, playerTurn) if aif.isSafeToPlay((x,y), yourOrScores, gameBoard) and len(newLoseOpportunities) < len(oldLoseOpportunities): #print "FOUND SOMETHING BETTER THAN LOOKAHEADONE: ", x,y bestMove= (x,y) bestBoard= newBoard #return move leading to that state if trapFlag == -1 and bestMove == slot: #print "OOOOOOOOOOOOH NOOOOooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo DON'T PLAY THERE" pass return bestMove, isBlockOrWin