Python Snake Wrap-Around Mode
Wrap-around mode is a rule change that sends the snake out of one side of the board and in through the other side. The wall check leaves the loop and a wrap block takes its place.
Wrapping left and right
The wrap block tests the x position right after the move. A head past one edge is set to the far edge on the same row.
# Wrap: the head leaves one side and enters the other
if head.xcor() > 290:
head.setx(-290)
if head.xcor() < -290:
head.setx(290)Wrapping up and down
Two more tests do the same job on the y axis. A head past the top is set to the bottom, and a head past the bottom is set to the top.
if head.ycor() > 290:
head.sety(-290)
if head.ycor() < -290:
head.sety(290)The self check stays
The body check keeps its old place after the wrap block. A bite into the body still calls reset_game and ends the run.
# Self: the head ran into the body, so the run ends
for segment in segments:
if segment.distance(head) < 20:
reset_game()
breakExample
# Snake - the classic arcade game, built lesson by lesson.
# Run it with: python snake.py
# Steer with the arrow keys. Press P to pause and R to restart.
import turtle
import time
import random
# The game window
screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.bgcolor("darkgreen")
screen.title("Snake")
screen.tracer(0)
# The border marks the edge of the board
border = turtle.Turtle()
border.speed(0)
border.color("white")
border.penup()
border.goto(-290, -290)
border.pendown()
for side in range(4):
border.forward(580)
border.left(90)
border.hideturtle()
# The snake head
head = turtle.Turtle()
head.speed(0)
head.shape("square")
head.color("lime")
head.penup()
head.goto(0, 0)
head.direction = "right"
# The food: one red circle on the board
food = turtle.Turtle()
food.speed(0)
food.shape("circle")
food.color("red")
food.penup()
# The body starts empty; the scores start at zero
segments = []
score = 0
high_score = 0
delay = 0.1
paused = False
# The pen writes the score at the top of the board
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
def move():
if head.direction == "up":
head.sety(head.ycor() + 20)
if head.direction == "down":
head.sety(head.ycor() - 20)
if head.direction == "left":
head.setx(head.xcor() - 20)
if head.direction == "right":
head.setx(head.xcor() + 20)
def go_up():
if head.direction != "down":
head.direction = "up"
def go_down():
if head.direction != "up":
head.direction = "down"
def go_left():
if head.direction != "right":
head.direction = "left"
def go_right():
if head.direction != "left":
head.direction = "right"
def new_food_spot():
x = random.randint(-14, 14) * 20
y = random.randint(-14, 14) * 20
food.goto(x, y)
def show_score():
pen.clear()
pen.write(f"Score: {score} High Score: {high_score}", align="center", font=("Courier", 20, "bold"))
def toggle_pause():
global paused
paused = not paused
def reset_game():
global score, high_score, delay
time.sleep(0.5)
head.goto(0, 0)
head.direction = "stop"
for segment in segments:
segment.hideturtle()
segments.clear()
if score > high_score:
high_score = score
score = 0
delay = 0.1
show_score()
new_food_spot()
show_score()
# The keyboard steers the snake
screen.listen()
screen.onkey(go_up, "Up")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
screen.onkey(go_right, "Right")
screen.onkey(toggle_pause, "p")
screen.onkey(reset_game, "r")
# The game loop: redraw, step the game unless paused, wait, repeat
while True:
screen.update()
if not paused:
# The body follows: each segment takes the place of the one ahead
for index in range(len(segments) - 1, 0, -1):
x = segments[index - 1].xcor()
y = segments[index - 1].ycor()
segments[index].goto(x, y)
if len(segments) > 0:
segments[0].goto(head.xcor(), head.ycor())
move()
# Wrap: the head leaves one side and enters the other
if head.xcor() > 290:
head.setx(-290)
if head.xcor() < -290:
head.setx(290)
if head.ycor() > 290:
head.sety(-290)
if head.ycor() < -290:
head.sety(290)
# Self: the head ran into the body, so the run ends
for segment in segments:
if segment.distance(head) < 20:
reset_game()
break
# Eat: the head reached the food
if head.distance(food) < 20:
new_food_spot()
new_segment = turtle.Turtle()
new_segment.speed(0)
new_segment.shape("square")
new_segment.color("lightgreen")
new_segment.penup()
segments.append(new_segment)
score = score + 10
if delay > 0.05:
delay = delay - 0.005
show_score()
time.sleep(delay)Key points
- The wall check is gone from the game loop
- Crossing 290 on the x axis sends the head to -290 on the x axis
- Crossing -290 on the x axis sends the head to 290 on the x axis
- The same swap applies on the y axis with sety
- A wall no longer ends a run in this mode
- Food, growth and the score work exactly as before
- A bite into the body still ends the run through reset_game
In this example, the program is the complete game with one block swapped. The window, the border, the head, the food and the score all set up as before. The loop still makes the body follow and then moves the head. The old wall check is gone at that point in the loop. A wrap block stands in its place with four tests. A head past 290 on x is set to -290 on x. A head past -290 on x is set to 290 on x. The y tests mirror the x tests with sety. No reset follows a crossing, so the run goes on. The self check still ends a run on a bite into the body. The eat check still grows the snake and raises the score. reset_game now serves the self check and the R key only.
Note
The white border still draws the board edge, even though the edge no longer ends a run
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
The head moves right and its x position passes 290. Where does the head appear?