Tic Tac Toe (3)
Contents
Tic Tac Toe (3)¶
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 Letter¶
Last time we looked at TTTBoard, which inherits from Board and also adds Tic Tac Toe specific features. Today we’ll look at the final two classes: TTTLetter and TTTGame.
# TTTLetter class
"""Implements the functionality of a letter in Boggle."""
from graphics import *
from board import *
class TTTLetter:
"""A TTT letter has several attributes that define it:
* _row, _col coordinates indicate its position in the grid (ints)
* _textObj denotes the Text object from the graphics module,
which has attributes such as size, style, color, etc
and supports methods such as getText(), setText() etc.
* _rect denotes the Rectangle object from the graphics module,
which has attributes such as color and supports methods such as
getFillColor(), setFillColor() etc.
"""
__slots__ = ['_row', '_col', '_textObj', '_rect']
def __init__(self, board, col=-1, row=-1, letter=""):
# variables needed for graphical testing
xInset = board.getXInset()
yInset = board.getYInset()
size = board.getSize()
win = board.getWin()
# set row and column attributes
self._col = col
self._row = row
# make rectangle and add to graphical window
p1 = Point(xInset + size * col, yInset + size * row)
p2 = Point(xInset + size * (col + 1), yInset + size * (row + 1))
self._rect = board._makeRect(p1, p2, "white")
# update text in center of rectangle
self._textObj = Text(self._rect.getCenter(), letter)
self._textObj.draw(win)
def getLetter(self):
"""Returns letter (text of type str) associated with self._textObj"""
return self._textObj.getText()
def setLetter(self, char):
self._textObj.setText(char)
if char == 'X':
self._rect.setFillColor("light blue")
elif char == 'O':
self._rect.setFillColor("pink")
else:
self._rect.setFillColor("white")
def __str__(self):
l, col, row = self.getLetter(), self._col, self._row
return "{} at Board position ({}, {})".format(l, col, row)
def __repr__(self):
return str(self)
# Would be in if __name__ == "__main__":
win = GraphWin("Tic Tac Toe", 400, 400)
board = Board(win, rows=3, cols=3)
letter = TTTLetter(board, 1, 1, "A")
letter2 = TTTLetter(board, 1, 2, "O")
letter3 = TTTLetter(board, 2, 1, "B")
letter2.setLetter("O")
print(letter2)
win.close()
Tic Tac Toe Game¶
Finally, let’s put it all together and implement the game logic in TTTGame.
from graphics import GraphWin
from tttboard import TTTBoard
from tttletter import TTTLetter
class TTTGame:
__slots__ = [ "_board", "_numMoves", "_player" ]
def __init__(self, win):
self._board = TTTBoard(win)
self._numMoves = 0
self._player = "X"
def doOneClick(self, point):
"""
Implements the logic for processing
one click. Returns True if play
should continue, and False if the game is over.
"""
# step 1: check for exit button and exit (return False)
if self._board.inExit(point):
# game over
return False
# step 2: check for reset button and reset game
elif self._board.inReset(point):
self._board.reset()
self._board.setStringToUpperText("")
self._numMoves = 0
self._player = "X"
# step 3: check if click is on a cell in the grid
elif self._board.inGrid(point):
# get the letter at the point the user clicked
tlet = self._board.getTTTLetterAtPoint(point)
# make sure this square is vacant
if tlet.getLetter() == "":
tlet.setLetter(self._player)
# valid move, so increment numMoves
self._numMoves += 1
# check for win or draw
winFlag = self._board.checkForWin(self._player)
if winFlag:
self._board.setStringToUpperText(self._player + " WINS!")
elif self._numMoves == 9:
self._board.setStringToUpperText("DRAW!")
# not a win or draw, swap players
else:
# set player to X or O
if self._player == "X":
self._player = "O"
else:
self._player = "X"
# keep going!
return True
# Would be in if __name__ == "__main__":
win = GraphWin("Tic Tac Toe", 400, 400)
game = TTTGame(win)
keepGoing = True
while keepGoing:
point = win.getMouse()
keepGoing = game.doOneClick(point)
win.close()