Could someone check the Minimax Algorithm correctly implemented?
tmp = game[:][:] is not doing what you think it is doing.  game[:] returns a slice of all the rows of game (so a list of columns).  To that, you apply the slice operator [:], which takes the slice of the row list (of columns), and returns a row list (of columns).  In short, game[:] is the same as game[:][:], which is the same as game[:][:][:][:][:].

In particular, tmp is list which contains references to the same column lists as game, so tmp[row][col] accesses exactly the same entry as game[row][col].  You have not created a temporary copy of game; you have created a copy of references to the same column list objects.

As such, you can remove tmp, and just set game[row][col] directly, and set it back to None like you are doing via tmp.



The code x, y = move[0], move[1] seems to be useless, since x and y are never used.



The minimax() function returns the best possible outcome for that player, but doesn’t return the move that corresponds to that outcome.  “You have a guaranteed winning move, but I’m not going to tell you what it is.”

You might want to return the move that corresponds to that outcome.