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()