CMU 15-112: Fundamentals of Programming and Computer Science
Capture The Flag From Lecture (No Timer)
Note: This code has been lightly cleaned up since lecture, but it's still messy. It may not follow our style guide, some design decisions are debatable, and it's not well documented. Still, if you'd like to work through a medium-sized timerless game this is a good resource.
from cmu_112_graphics import *
import random
###########################################
# Helpers
###########################################
def make2dList(rows, cols, startValue):
return [[startValue]*cols for row in range(rows)]
def isInBounds(app, row, col):
return 0 <= row < len(app.board) and 0 <= col < len(app.board[0])
def getCell(app, x, y):
cellWidth = app.width // len(app.board[0])
cellHeight = app.height // len(app.board)
row = y // cellHeight
col = x // cellWidth
return row, col
def getCellBounds(app, row, col):
cellWidth = app.width // len(app.board[0])
cellHeight = app.height // len(app.board)
left = cellWidth * col
top = cellHeight * row
right = left + cellWidth
bottom = top + cellHeight
return left, top, right, bottom
###########################################
# Model
###########################################
def randomlyPlaceObjectOnBoard(app, object):
while True:
row = random.randrange(len(app.board))
col = random.randrange(len(app.board[0]))
if app.board[row][col] == '':
app.board[row][col] = object
break
def findObjectInBoard(app, object):
for row in range(len(app.board)):
for col in range(len(app.board[0])):
if app.board[row][col] == object:
return (row, col)
return (-1, -1)
def initRound(app):
app.gameOver = False
app.winner = None
app.board = make2dList(15, 15, '')
randomlyPlaceObjectOnBoard(app, 'player1')
randomlyPlaceObjectOnBoard(app, 'player2')
randomlyPlaceObjectOnBoard(app, 'flag1')
randomlyPlaceObjectOnBoard(app, 'flag2')
def appStarted(app):
app.wins = [0, 0] # [player1 wins, player2 wins]
initRound(app)
###########################################
# Controller
###########################################
def playerKeyPressed(app, event, keys, player):
rightKey, leftKey, upKey, downKey = keys
currRow, currCol = findObjectInBoard(app, player)
if event.key == rightKey:
newRow, newCol = currRow, currCol + 1
elif event.key == leftKey:
newRow, newCol = currRow, currCol - 1
elif event.key == upKey:
newRow, newCol = currRow - 1, currCol
elif event.key == downKey:
newRow, newCol = currRow + 1, currCol
if not isInBounds(app, newRow, newCol): return
targetObject = app.board[newRow][newCol]
if targetObject == '':
app.board[currRow][currCol] = ''
app.board[newRow][newCol] = player
elif targetObject.startswith('flag') and targetObject[-1] == player[-1]:
app.board[currRow][currCol] = ''
app.board[newRow][newCol] = player
app.wins[int(player[-1])-1] += 1 # player1 indexes into wins[0]
app.gameOver = True
app.winner = player
def keyPressed(app, event):
if app.gameOver:
if event.key == 'r':
initRound(app)
return
playerOneKeys = ('Right', 'Left', 'Up', 'Down')
playerTwoKeys = ('d', 'a', 'w', 's')
if event.key in playerOneKeys:
playerKeyPressed(app, event, playerOneKeys, 'player1')
elif event.key in playerTwoKeys:
playerKeyPressed(app, event, playerTwoKeys, 'player2')
def mousePressed(app, event):
if app.gameOver: return
row, col = getCell(app, event.x, event.y)
if app.board[row][col] == '':
app.board[row][col] = 'rock'
###########################################
# View
###########################################
def drawCell(app, canvas, row, col):
left, top, right, bottom = getCellBounds(app, row, col)
canvas.create_rectangle(left, top, right, bottom)
if app.board[row][col] == 'player1':
canvas.create_oval(left, top, right, bottom, fill='red')
if app.board[row][col] == 'player2':
canvas.create_oval(left, top, right, bottom, fill='blue')
if app.board[row][col] == 'rock':
canvas.create_oval(left, top, right, bottom, fill='grey')
if app.board[row][col] == 'flag1':
canvas.create_polygon(left, top, left, bottom, right,
top + (bottom - top) // 2, fill='red'
)
if app.board[row][col] == 'flag2':
canvas.create_polygon(left, top, left, bottom, right,
top + (bottom - top) // 2, fill='blue'
)
def drawGameOver(app, canvas):
spacer = 60
messages = [
f'{app.winner.title()} won!',
f'Player1 Wins: {app.wins[0]}',
f'Player2 Wins: {app.wins[1]}',
f'Press \'r\' to play again'
]
for i in range(len(messages)):
canvas.create_text(app.width//2,app.height//4 + i*spacer,
text=messages[i], font='Arial 30'
)
def redrawAll(app, canvas):
if app.gameOver:
drawGameOver(app, canvas)
return
for row in range(len(app.board)):
for col in range(len(app.board[0])):
drawCell(app, canvas, row, col)
runApp(width=500, height=500)