Tic Tac Toe (2)
Contents
Tic Tac Toe (2)¶
In today’s lecture, we will continue our discussion on building a simple text-based board game (Tic Tac Toe). In the process, we will learn about the benefits of inheritance, encapsulation and more generally of object-oriented design.
Tic Tac Toe Board¶
We discussed the Board
class last time which is the base layer of our game. We start by importing the graphics package and Board
class, which will now just use. At this point we don’t need to worry too much about the details of their implementation!
from graphics import *
from board import Board
Using the Board
Class¶
We can use the Board
class by defining an instance (object) of the class.
win = GraphWin("Tic Tac Toe", 400, 400)
board = Board(win) # create the board using default values
win.close()
Extending the Board Class¶
We can now inherit and extend the Board
class to create a Tic Tac Toe Board.
A tic-tac-toe board is composed of a grid of tic-tac-toe letters.
We will define tic-tac-toe letters it their own class TTTLetter
to separate out the functionality of a single later. Let’s ignore those details for now (abstraction!).
from tttletter import TTTLetter
from graphics import *
# let's just see what methods we have to work with when using TTTLetters
help(TTTLetter)
# Tic Tac Toe board class
"""Extends the Board class with specific features
required for Tic Tac Toe"""
# import modules and classes
from graphics import *
from tttletter import TTTLetter
from board import Board
class TTTBoard(Board):
"""TTT Board class implements the functionality of a
Tic Tac Toe board. It inherits from the Board class and
extends it by creating a grid of TTTLetters."""
__slots__ = ['_grid']
def __init__(self, win):
super().__init__(win)
# initialize a grid of TTTLetters (list of lists)
self._grid = []
for col in range(self._cols):
grid_col = []
# next part could be a list comprehension!
for row in range(self._rows):
# create new TTTLetter, specifying grid coord
letter = TTTLetter(self.getBoard(), col, row)
# add TTTLetter to column
grid_col.append(letter)
# add column to grid
self._grid.append(grid_col)
def getTTTLetterAtPoint(self, point):
"""Returns the TTTLetter at point (a screen coord tuple)"""
if self.inGrid(point):
(col, row) = self.getPosition(point)
return self._grid[col][row]
else:
return None
# reset all letter objects in grid
def reset(self):
"""Clears the TTT board by clearing letters."""
for x in range(self._cols):
for y in range(self._rows):
# get letter out of grid and reset it
let = self._grid[x][y]
let.setLetter("")
# checking for win methods:
def _checkRows(self, letter):
"""Check rows for a win (3 in a row)."""
for row in range(self._rows):
count = 0
for col in range(self._cols):
tttLet = self._grid[col][row]
# check how many times letter appears
if tttLet.getLetter() == letter:
count +=1
# if this is a winning row
if count == self._rows:
return True
# no winning row found
return False
def _checkCols(self, letter):
"""Check columns for a win (3 in a row)."""
for col in range(self._cols):
count = 0
for row in range(self._rows):
tttLet = self._grid[col][row]
# check how many times letter appears
if tttLet.getLetter() == letter:
count +=1
# if this is a winning row
if count == self._cols:
return True
# if no winning rows
return False
def _checkDiagonals(self, letter):
"""Check diagonals for a win (3 in a row)."""
# counts for primary and secondary diagonal
countPrimary, countSecond = 0, 0
for col in range(self._cols):
for row in range(self._rows):
tttLet = self._grid[col][row]
# update count for primary diagonal
if (row == col and tttLet.getLetter() == letter):
countPrimary += 1
# update count for secondary diagonal
if (row + col == self._rows - 1 and tttLet.getLetter() == letter):
countSecond += 1
# return true if either return in win
return countPrimary == self.getRows() or countSecond == self.getRows()
def checkForWin(self, letter):
"""Check board for a win."""
rowWin = self._checkRows(letter)
colWin = self._checkCols(letter)
diagWin = self._checkDiagonals(letter)
return rowWin or colWin or diagWin
win = GraphWin("Tic Tac Toe", 400, 400)
tttboard = TTTBoard(win)
tttboard.getTTTLetterAtPoint(Point(75, 75)).setLetter("X")
tttboard.getTTTLetterAtPoint(Point(150, 150)).setLetter("O")
tttboard.getRows(), tttboard.getCols()
# calls str of TTTLetter
print(tttboard.getTTTLetterAtPoint(Point(75,75)))
tttboard.reset()
# example board state
# X O O
# X
# O O O
tttboard.getTTTLetterAtPoint(Point(75,75)).setLetter("X")
tttboard.getTTTLetterAtPoint(Point(125,75)).setLetter("O")
tttboard.getTTTLetterAtPoint(Point(175,75)).setLetter("O")
tttboard.getTTTLetterAtPoint(Point(75,125)).setLetter("")
tttboard.getTTTLetterAtPoint(Point(125,125)).setLetter("X")
tttboard.getTTTLetterAtPoint(Point(175,125)).setLetter("")
tttboard.getTTTLetterAtPoint(Point(75,175)).setLetter("O")
tttboard.getTTTLetterAtPoint(Point(125,175)).setLetter("O")
tttboard.getTTTLetterAtPoint(Point(175,175)).setLetter("O")
tttboard._checkRows("O")
tttboard._checkCols("O")
tttboard._checkDiagonals("X")
tttboard._checkDiagonals("O")
tttboard.checkForWin("X")
tttboard.checkForWin("O")
tttboard.reset()
win.close()