You can write Pong game code in Python with just the built-in turtle module: two stretched squares for paddles, a circle for the ball, keyboard bindings, and a loop that moves the ball and checks for bounces. No installs needed:
import turtle
screen = turtle.Screen()
screen.tracer(0) # draw frames yourself for smooth motion
I ran the full game below on Python 3.12.5 on Windows; the screenshot is the real game window at the end of a match.
We’ll build the window, paddles and ball, add keyboard controls, handle bounces and scoring, test the collision logic, and add a simple computer opponent.
Pong game code in Python (full program)
Save this as pong.py and run it. Player A uses W and S, Player B uses the Up and Down arrows, and the first to 3 points wins:
import time
import turtle
WIDTH, HEIGHT = 800, 600
WINNING_SCORE = 3
screen = turtle.Screen()
screen.title("Pong")
screen.bgcolor("black")
screen.setup(WIDTH, HEIGHT)
screen.tracer(0) # we redraw manually for smooth movement
def make(shape, x, stretch_len=1, stretch_wid=1):
t = turtle.Turtle(shape)
t.color("white")
t.penup()
t.shapesize(stretch_wid=stretch_wid, stretch_len=stretch_len)
t.goto(x, 0)
return t
left = make("square", -350, stretch_wid=5) # paddles are stretched squares
right = make("square", 350, stretch_wid=5)
ball = make("circle", 0)
ball.dx, ball.dy = 4, 3
pen = turtle.Turtle(visible=False)
pen.color("white")
pen.penup()
pen.goto(0, 250)
score = {"left": 0, "right": 0}
def draw_score():
pen.clear()
pen.write(f"Player A: {score['left']} Player B: {score['right']}", align="center", font=("Courier", 20, "normal"))
def move(paddle, dy):
y = paddle.ycor() + dy
paddle.sety(max(-250, min(250, y))) # keep the paddle on screen
screen.listen()
screen.onkeypress(lambda: move(left, 25), "w")
screen.onkeypress(lambda: move(left, -25), "s")
screen.onkeypress(lambda: move(right, 25), "Up")
screen.onkeypress(lambda: move(right, -25), "Down")
draw_score()
while max(score.values()) < WINNING_SCORE:
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
if abs(ball.ycor()) > 290: # bounce off top and bottom
ball.dy *= -1
for paddle, side in ((right, 1), (left, -1)):
if 330 < ball.xcor() * side < 350 and abs(ball.ycor() - paddle.ycor()) < 50:
ball.dx = -abs(ball.dx) * side # bounce back toward the other player
if abs(ball.xcor()) > 390: # someone missed
score["left" if ball.xcor() > 0 else "right"] += 1
print(f"Point! A {score['left']} - B {score['right']}")
ball.goto(0, 0)
ball.dx *= -1
draw_score()
screen.update()
time.sleep(1 / 120)
winner = "A" if score["left"] == WINNING_SCORE else "B"
pen.goto(0, 0)
pen.write(f"Player {winner} wins!", align="center", font=("Courier", 28, "bold"))
turtle.done()
Output:
Point! A 1 - B 0
Point! A 1 - B 1
Point! A 2 - B 1
Point! A 2 - B 2
Point! A 3 - B 2

turtle.done() keep it open until you do.The console also prints each point as it happens, which I find handy for debugging the scoring.
How the Pong game works
screen.tracer(0)turns off automatic redraws, andscreen.update()draws each frame once. Without this, the ball flickers and crawls.- Paddles are square turtles stretched to five times their height with
shapesize(). - The ball moves by
dxanddyeach frame; flipping the sign of one reverses that direction. onkeypress()andlisten()connect keys to the paddle-moving functions.time.sleep(1 / 120)caps the speed at about 120 frames per second.
The main loop is a while loop that ends when a player reaches the winning score; see infinite loops in Python for other ways to structure game loops.
Testing the Pong ball and paddle collisions
In my experience, bounce bugs are the most common Pong problem you’ll hit. Pull the checks into small functions and test them without opening a window:
def wall_bounce(y, dy, limit=290):
return -dy if abs(y) > limit else dy
def paddle_hit(ball_x, ball_y, paddle_y, side):
"""side = 1 for the right paddle, -1 for the left one."""
return 330 < ball_x * side < 350 and abs(ball_y - paddle_y) < 50
tests = [
("ball at top wall", wall_bounce(295, 3) == -3),
("ball mid-screen keeps going", wall_bounce(100, 3) == 3),
("right paddle hit", paddle_hit(340, 20, 0, 1)),
("right paddle miss (too high)", not paddle_hit(340, 80, 0, 1)),
("left paddle hit", paddle_hit(-345, -30, -10, -1)),
("ball near left paddle but past it", not paddle_hit(-360, 0, 0, -1)),
]
for name, ok in tests:
print(f"{'PASS' if ok else 'FAIL'} {name}")
Output:
PASS ball at top wall
PASS ball mid-screen keeps going
PASS right paddle hit
PASS right paddle miss (too high)
PASS left paddle hit
PASS ball near left paddle but past it

You’ll notice the paddle check only fires in a thin strip in front of the paddle. That stops the ball from “sticking” and bouncing back and forth inside it.
How do you add a computer player to Pong?
Move the computer’s paddle toward the ball each frame, but cap its speed so it can miss. That cap is your difficulty setting:
def ai_paddle(paddle_y, ball_y, speed=6):
"""Move the computer paddle toward the ball, but no faster than `speed` per frame."""
gap = ball_y - paddle_y
return paddle_y + max(-speed, min(speed, gap))
paddle_y = 0
for frame, ball_y in enumerate([0, 30, 60, 90, 120, 120, 120, 100], start=1):
paddle_y = ai_paddle(paddle_y, ball_y)
print(f"frame {frame}: ball y {ball_y:>4} | paddle y {paddle_y:>4}")
Output:
frame 1: ball y 0 | paddle y 0
frame 2: ball y 30 | paddle y 6
frame 3: ball y 60 | paddle y 12
frame 4: ball y 90 | paddle y 18
frame 5: ball y 120 | paddle y 24
frame 6: ball y 120 | paddle y 30
frame 7: ball y 120 | paddle y 36
frame 8: ball y 100 | paddle y 42

To use it, you’d replace Player B’s key bindings with right.sety(ai_paddle(right.ycor(), ball.ycor())) inside the main loop.
Ideas to improve your Pong game
- Speed the ball up a little after every paddle hit.
- Add sound with
winsound.Beep()on Windows. - Change the bounce angle based on where the ball hits the paddle.
- Rebuild it in Pygame for sprites, sound and a steadier frame rate.
If you liked this, try these other Python game projects:
- Tic tac toe game in Python
- Rock paper scissors in Python
- Python turtle graphics
- and, or and not in Python
Frequently asked questions
How do I make a Pong game in Python?
Use the turtle module: create paddle and ball turtles, bind keys with onkeypress(), and move the ball in a loop that checks for bounces and scores.
Do I need Pygame for Pong?
No. The built-in turtle module is enough for a simple version. Pygame is better if you want sound, sprites and smoother timing.
Why is my turtle Pong game slow or flickering?
Call screen.tracer(0) once and screen.update() every frame.
Why don’t my paddle keys work?
You need screen.listen(), and the game window must have focus. Click it once if needed.
How do I make the ball faster over time?
Multiply ball.dx and ball.dy by something like 1.05 after each paddle hit.
Where is the turtle module documented?
See turtle in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn