diff --git a/funcs/games/gameLoops.py b/funcs/games/gameLoops.py index d1fcb9e..db6564b 100644 --- a/funcs/games/gameLoops.py +++ b/funcs/games/gameLoops.py @@ -45,6 +45,7 @@ async def runHex(channel,command,user): try: response, showImage, deleteImage, gameDone, gwendoTurn = hexAI(str(channel.id)) except: + response, showImage, deleteImage, gameDone, gwendoTurn = "An AI error occured",False,False,False,False logThis("AI error (error code 1520)") await channel.send(response) logThis(response,str(channel.id)) diff --git a/funcs/games/hex.py b/funcs/games/hex.py index bbeeac4..f005fbc 100644 --- a/funcs/games/hex.py +++ b/funcs/games/hex.py @@ -227,7 +227,7 @@ def undoHex(channel, user): # Update the board hexDraw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear - return "You undid", True, True, False, False + return "You undid your last move at {}".format(lastMove), True, True, False, False else: # Sassy return "Nice try. You can't undo your opponent's move. ", False, False, False, False @@ -245,25 +245,44 @@ def hexAI(channel): with open("resources/games/hexGames.json", "r") as f: data = json.load(f) + + if len(data[channel]["gameHistory"]): + lastMove = data[channel]["gameHistory"][-1] + else: + lastMove = (5,5) + + # These moves are the last move +- 2. + moves = [[(lastMove[0]+j-2,lastMove[1]+i-2) for i in range(5) if lastMove[1]+i-2 in range(11)] for j in range(5) if lastMove[0]+j-2 in range(11)] + moves = sum(moves,[]) + movesCopy = moves.copy() + for move in movesCopy: + if board[move[0]][move[1]] != 0: + moves.remove(move) + chosenMove = random.choice(moves) + + """ + GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue + if len(data[channel]["gameHistory"]) == 0: + return placeHex(channel,"F6", "Gwendolyn") # If starting, start in the middle board = data[channel]["board"] difficulty = data[channel]["difficulty"] possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0] - judgements = [-math.inf]*len(possiblePlaces) # All possible moves are yet to be judged - GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue - + judgements = [float('nan')]*len(possiblePlaces) # All possible moves are yet to be judged + current_score = evaluateBoard(board)[0] for i in possiblePlaces: testBoard = copy.deepcopy(board) - testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 1 + testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = GwenColor if evaluateBoard(testBoard)[0] != current_score: # only think about a move if it improves the score (it's impossible to get worse) # Testing a move and evaluating it judgements[i] = minimaxHex(testBoard,difficulty,-math.inf,math.inf,GwenColor==2) logThis("Best score for place {} is {}".format((i // BOARDWIDTH,i % BOARDWIDTH),judgements[i])) - bestScore = max(judgements) if (GwenColor == 1) else min(judgements) + bestScore = max(judgements) if (GwenColor == 1) else min(judgements) # this line has an error indices = [i for i, x in enumerate(judgements) if x == bestScore] # which moves got that score? i = random.choice(indices) chosenMove = (i // BOARDWIDTH , i % BOARDWIDTH) + """ placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1) logThis("ChosenMove is {} at {}".format(chosenMove,placement)) return placeHex(channel,placement, "Gwendolyn") @@ -303,7 +322,6 @@ def evaluateBoard(board): if scores[player] == 0: winner = player break # We don't need to check the other player's score, if player1 won. - return scores[2]-scores[1], winner @@ -324,6 +342,7 @@ def minimaxHex(board, depth, alpha, beta, maximizingPlayer): maxEval = max(maxEval, evaluation) alpha = max(alpha, evaluation) if beta <= alpha: + logThis("Just pruned something!") break return maxEval else: # blue player predicts next move @@ -337,6 +356,7 @@ def minimaxHex(board, depth, alpha, beta, maximizingPlayer): minEval = min(minEval, evaluation) beta = min(beta, evaluation) if beta <= alpha: + logThis("Just pruned something!") break return minEval