A few thoughts from the small to the big:
- `not(A) and not(B) and not(C)` can be rearranged to `not(A or B or C)` which is technically shorter. It's called DeMorgan's law!
So it turns out that your checks on line 18 and 54 are the exact same but negated.
- You could offload those checks into a function:
return (board == board == ...)
And then you don't have to repeat yourself twice:
if(game_over(board) and not cheat):
- The ideal way to DRY up your code is to write seperate functions for checking a single row/column/diagonal. It will probably make your code *longer* but DRYer for sure.
Think about how you would solve a 100x100 tic tac toe puzzle!