Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set your subtitle preferences in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Discard Incorrect Game States

00:00 Discard Incorrect Game States. In order to reject invalid game states, you’ll implement a familiar post-initialization hook in your GameState class that delegates the processing to another function.

00:35 The validating function, validate_game_state(), receives an instance of the game state, which in turn contains the grid of cells and the starting player.

00:45 You’ll use this information, but first you’ll split the validation into a few smaller and more focused stages by delegating bits of the state further down in your validators module.

01:17 Your new helper function serves as an entry point to the game state validation by calling a few subsequent functions that you’ll define presently. To prevent instantiating a game state with an incorrect number of a player’s marks in the grid, such as the one that you stumbled on earlier on, you must take the proportion of naughts to crosses into account.

02:00 At any time, the number of marks left by one player must be either the same or greater by exactly one compared to the number of marks left by the other player.

02:09 Initially, there are no marks, so the number of Xs and Os is equal to zero. When the first player makes a move, they’ll have one more mark than their opponent, but as soon as the other player makes their move, the proportion evens out again, and so on.

02:25 To signal an invalid state, you raise a custom exception defined in another module.

02:42 It’s customary to have empty classes extend the built-in Exception type in Python without specifying any methods or attributes in them. Such classes exist solely for their names, which convey enough information about the error that occurred at runtime.

02:56 Notice that you don’t need to use the pass statement or the ellipsis literal (...) as a class body placeholder if you use a docstring, which can provide additional information.

03:07 Another game state inconsistency related to the number of marks left on the grid has to do with the starting player’s mark, which may be wrong.

03:35 The player who left more marks on the grid is guaranteed to be the starting player. If not, then you know something must have gone wrong. Because of the way Mark was defined, you can directly compare the starting player’s mark to a string literal.

03:58 Finally, there can be only one winner, and depending on who started the game, the ratio of Xs and Os left on the grid will be different.

04:28 A starting player has an advantage, so when they win, they’ll have left more marks than their opponent. Conversely, the second player is at a disadvantage so they can only win the game by making an equal number of moves as the starting player.

05:20 You are almost done with encapsulating the tic-tac-toe game’s rules in Python code, but there’s still one more important piece missing. In the next video, you’ll write code to systematically produce new game states by simulating players’ moves.

Become a Member to join the conversation.