def getRandomMove(): state = gameState.getState() myPlayerID = gameController.getMyPlayerID(state) possibleMoves = gameController.allMoves(state, myPlayerID) pawns = list( filter(lambda pawn: len(possibleMoves[pawn]) > 0, possibleMoves.keys()) ) # Get only pawns that have at least 1 possible move if len(pawns) == 0: print('!!ERROR!! No possible moves for player: ' + gameController.getMyPlayerID(state)) oldField = random.choice(pawns) newField = random.choice(possibleMoves[oldField]) return oldField, newField
def evaluate(state): # player 2 maximizes evaluation, player 1 minimizes evaluation currentPositions = state['pawns'] players = state['players'] centerline = int(7) for player in players: playerID = player['id'] boundary = player['boundary'] maxPlayer = gameController.getMyPlayerID(state) vertDist = 0 horDist = 0 for pawn in currentPositions[playerID]: if pawn not in player['goalFields']: vertDist += abs(boundary - const.VERT_POS[int(pawn)]) horDist += abs(centerline - const.HOR_POS[int(pawn)]) if playerID == maxPlayer: maxPlayerVertDist = vertDist maxPlayerHorDist = horDist else: minPlayerVertDist = vertDist minPlayerHorDist = horDist endGameMaxPlayer = gameOver(state, maxPlayer) endGameMinPlayer = gameOver(state, gameController.getOpponentID(state)) m = evalWeight return m * (minPlayerVertDist - maxPlayerVertDist) + (1 - m) * (minPlayerHorDist - maxPlayerHorDist) + const.E_CONST* (endGameMaxPlayer - endGameMinPlayer)
def getBestMove(bestMaxMove): state = gameState.getState() print('Calculating MinMax...\n') startTime = time.time() minMax(state, maxDepth, -const.M_CONST, const.M_CONST, True) calculationTime = time.time() - startTime print('Calculated in: ' + str(round(calculationTime, 2)) + ' seconds') calculationTimes.append(calculationTime) print('Average calculation time so far: ' + str(round(np.mean(calculationTimes), 2)) + ' seconds') print('Max calculation time so far: ' + str(round(np.max(calculationTimes), 2)) + ' seconds') print('Min calculation time so far: ' + str(round(np.min(calculationTimes), 2)) + ' seconds') print('Total calculation time so far: ' + str(round(np.sum(calculationTimes), 2)) + ' seconds\n') print('No. of evaluated moves: {0}'.format(nodesEvaluated)) allNodesEvaluated.append(nodesEvaluated) # averageNodesEvaluated = sumNodesEvaluated / mainLoopIterations print('Average no. of evaluated moves so far: {0}'.format(round(np.mean(allNodesEvaluated), 0))) print('Max no. of evaluated moves so far: {0}'.format(np.max(allNodesEvaluated))) print('Min no. of evaluated moves so far: {0}'.format(np.min(allNodesEvaluated))) print('Total no. of evaluated moves so far: {0}'.format(np.sum(allNodesEvaluated))) if len(bestMaxMove) == 0: print('!!ERROR!! No possible moves for player: ' + str(gameController.getMyPlayerID(state))) moves = helper.maxes(bestMaxMove, key=lambda x: x[2]) # find all moves that has the same maximum evaluation value move = random.choice(moves[1]) # moves[0] - max evaluation value, moves[1] - list of moves with the maximum evaluation value oldField = move[0] newField = move[1] return oldField, newField
def printAllPossibleMoves(possibleMoves): state = gameState.getState() myPlayerID = gameController.getMyPlayerID(state) if showMoveEvaluation: print('Current evaluation: {0}'.format(evaluate(state))) for key, value in possibleMoves.items(): nextFields = [] for newField in value: if showMoveEvaluation: nextFields.append( evaluatePossibleMove((key, newField), myPlayerID)) else: nextFields.append(newField) print('Pawn {0} can move to {1}'.format(key, nextFields)) print('')
def getRandomBestMove(bestMaxMove): state = gameState.getState() print('Calculating MinMax...') startTime = time.time() minMax(state, maxDepth, -const.M_CONST, const.M_CONST, True) calculationTime = time.time() - startTime print('Calculated in: ' + str(round(calculationTime, 2)) + ' seconds') calculationTimes.append(calculationTime) print('Average calculation time so far:' + str(round(mean(calculationTimes), 2))) if len(bestMaxMove) == 0: print('!!ERROR!! No possible moves for player: ' + str(gameController.getMyPlayerID(state))) move = random.choice(bestMaxMove) oldField = move[0] newField = move[1] return oldField, newField
def minMax(state,depth,alpha,beta,maximizingPlayersTurn): # MinMax algorithm global nodesEvaluated maxPlayer = gameController.getMyPlayerID(state) minPlayer = gameController.getOpponentID(state) # TODO: most often the game is over, bc in the previous move the opponent won the game # can it be that we won the game bc of the previous move of the opponent? if depth == 0 or gameOver(state,maxPlayer) or gameOver(state,minPlayer): return evaluate(state) if maximizingPlayersTurn: playerId = maxPlayer bestEval = -const.M_CONST else: playerId = minPlayer bestEval = const.M_CONST possibleMoves = gameController.allMoves(state, playerId) # Evaluate first level # TODO: refactor if depth == maxDepth and maximizingPlayersTurn: sortedMoves = [] for pawn,move in ((p,i) for p in possibleMoves for i in possibleMoves[p]): newState = copy.deepcopy(state) newState = gameController.makeMove(newState, pawn, move, playerId) nodesEvaluated += 1 sortedMoves.append((evaluate(newState), pawn, move)) sortedMoves.sort(reverse = True) possibleMoves = list(map(lambda x : (x[1], x[2]), sortedMoves)) for possibleMove in possibleMoves: pawn = possibleMove[0] move = possibleMove[1] newState = copy.deepcopy(state) newState = gameController.makeMove(newState, pawn, move, playerId) nodesEvaluated += 1 evaluation = minMax(newState, depth - 1, alpha, beta, not maximizingPlayersTurn) if maximizingPlayersTurn: if maxDepth == depth and evaluation >= bestEval: bestMaxMove.append((pawn, move, evaluation)) bestEval, alpha, beta = updateEvaluation(maximizingPlayersTurn, bestEval, evaluation, alpha, beta) if pruning and beta < alpha: break else: for pawn,move in ((p,i) for p in possibleMoves for i in possibleMoves[p]): newState = copy.deepcopy(state) newState = gameController.makeMove(newState, pawn, move, playerId) nodesEvaluated += 1 evaluation = minMax(newState, depth - 1, alpha, beta, not maximizingPlayersTurn) if maximizingPlayersTurn: if maxDepth == depth and evaluation >= bestEval: bestMaxMove.append((pawn, move, evaluation)) bestEval, alpha, beta = updateEvaluation(maximizingPlayersTurn, bestEval, evaluation, alpha, beta) if pruning and beta < alpha: break return bestEval
def getPossibleMoves(): state = gameState.getState() myPlayerID = gameController.getMyPlayerID(state) possibleMoves = gameController.allMoves(state, myPlayerID) return possibleMoves