Skip to content

Commit 82b8f6c

Browse files
authored
Add racingShapes game
1 parent 0b67e1a commit 82b8f6c

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

racingShapes.py

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
"""
2+
racingShapes.py
3+
A game where shapes race froma start line to a finish line.
4+
The movements are randomised, so different shapes can win in different runs.
5+
"""
6+
7+
import turtle, time, random
8+
9+
10+
def drawShape(sides, color):
11+
"""Draws a shape with the specified number of sides and color.
12+
If sides is None, then a circle is drawn."""
13+
turtle.pencolor(color)
14+
turtle.pensize(5)
15+
turtle.left(90) # Draw the right-hand edge first, vertically
16+
if sides is None:
17+
turtle.circle(50)
18+
else:
19+
for i in range(sides):
20+
turtle.forward(50)
21+
turtle.left(360/sides)
22+
turtle.right(90) # Reverses the turn left above (restores original direction)
23+
24+
def drawVerticalLine(x):
25+
"""Draws a vertical line at the specified x coordinate."""
26+
turtle.pencolor("white")
27+
turtle.pensize(8)
28+
moveTo(x,300)
29+
turtle.goto(x,-300)
30+
31+
def moveTo(x,y):
32+
"""Moves the turtle to a new x and y coordinate without drawing a line."""
33+
turtle.penup()
34+
turtle.goto(x,y)
35+
turtle.pendown()
36+
37+
class Player:
38+
"""Class representing each player (shape)"""
39+
40+
def __init__(self, name, sides, color, x, y):
41+
"""Constructor. Name is a string, sides is the number of sides for the shape
42+
(or None for a circle), color is the shape's color, x and y are the starting
43+
coordinates of the shape."""
44+
self.name = name
45+
self.sides = sides
46+
self.color = color
47+
# Coordinates for the current position of the shape
48+
self.x = x
49+
self.y = y
50+
51+
def draw(self):
52+
"""Draws the shape at its current x and y coordinates."""
53+
moveTo(self.x, self.y)
54+
drawShape(self.sides, self.color)
55+
56+
def move(self):
57+
"""Moves the shape horizontally by a small, random amount."""
58+
self.x = self.x + random.randrange(2,8)
59+
60+
class Game:
61+
"""Class representing an instance of a game"""
62+
63+
# x coordinates for the start and finish lines
64+
finishLineX = 300
65+
startLineX = -300
66+
67+
def __init__(self):
68+
"""Constructor - initialses the window and creates 4 players."""
69+
self.window = turtle.Screen()
70+
self.window.bgcolor("yellow")
71+
turtle.pensize(5)
72+
turtle.tracer(0, 0) # Turns off auto-updating of screen when the turtle is moved.
73+
self.players = [
74+
Player("triangle", 3, "blue", self.startLineX, 250),
75+
Player("sqaure", 4, "green", self.startLineX, 100),
76+
Player("hexagon", 6, "aqua", self.startLineX, -100),
77+
Player("circle", None, "purple", self.startLineX, -250)
78+
]
79+
80+
def winner(self):
81+
"""Gets the winning player if there is one, otherwise returns None."""
82+
# Get the player with the largest x value
83+
firstPlace = sorted(self.players, key=lambda p:p.x, reverse=True)[0]
84+
if firstPlace.x > self.finishLineX:
85+
# Passed the finish line, so is the winner
86+
return firstPlace
87+
# Otherwise there isn't a winner yet
88+
return None
89+
90+
def playMoves(self):
91+
"""Moves each player by a small rnadom amount."""
92+
for player in self.players:
93+
player.move()
94+
95+
def writeWinner(self):
96+
"""Writes the winner at the bottom of the sreen."""
97+
moveTo(0, -350)
98+
turtle.pencolor("black")
99+
turtle.write("The winner is " + self.winner().name, font=('Arial', 30, 'bold'), align="center")
100+
moveTo(0, -385)
101+
turtle.write("Click the screen to play again", font=('Arial', 12, 'bold'), align="center")
102+
103+
def writeTitle(self):
104+
"""Writes the title at the top of the screen."""
105+
moveTo(0, 330)
106+
turtle.pencolor("black")
107+
turtle.write("Racing shapes!", font=('Courier', 50, 'italic'), align="center")
108+
109+
def writeCountDown(self, num):
110+
"""Writes a large countdown number in the middle of the screen."""
111+
moveTo(0, 0)
112+
turtle.pencolor("red")
113+
turtle.write(
114+
str(num)+" ", # extra space to prevent italic number being partially cut off
115+
font=('Arial black', 100, 'italic'),
116+
align="center"
117+
)
118+
119+
def drawFrame(self):
120+
"""Blanks the window and redraws everything, based on the current state of the game."""
121+
self.window.reset()
122+
self.writeTitle()
123+
drawVerticalLine(self.finishLineX)
124+
drawVerticalLine(self.startLineX)
125+
for player in self.players:
126+
player.draw()
127+
128+
# Hide the small shape indicating the turtle's position
129+
turtle.hideturtle()
130+
# Manually update the screen (draw the lines), since tracer(0,0) was used in constructor
131+
turtle.update()
132+
133+
def play(self):
134+
"""Plays the game."""
135+
136+
# Refresh rate. 25 to 30 fps is fast enough that the human eye percieves movement
137+
# rather than still images.
138+
framesPerSec = 1/30
139+
140+
# Begin with the countdown
141+
for i in range(3, 0, -1):
142+
self.drawFrame()
143+
self.writeCountDown(i)
144+
time.sleep(1)
145+
146+
# Loop through the players making their moves until there is a winner.
147+
while self.winner() is None:
148+
self.playMoves()
149+
self.drawFrame()
150+
time.sleep(framesPerSec)
151+
self.writeWinner()
152+
153+
''' For debugging purposes, write the final x coordinate for each player
154+
for player in self.players:
155+
moveTo(player.x, player.y)
156+
turtle.write(str(player.x))'''
157+
158+
# Restart if/when screen is clicked
159+
self.window.onscreenclick(self.restart)
160+
161+
def restart(self, _1, _2):
162+
"""Resets each player and plays the game again."""
163+
self.window.onscreenclick(None) # Disable click events
164+
for player in self.players:
165+
player.x = self.startLineX
166+
self.play()
167+
168+
# Create a new game and play it
169+
game = Game()
170+
game.play()

0 commit comments

Comments
 (0)