[python] How do I restart a program based on user input?

I'm trying to restart a program using an if-test based on the input from the user.

This code doesn't work, but it's approximately what I'm after:

answer = str(raw_input('Run again? (y/n): '))

if answer == 'n':
   print 'Goodbye'
   break
elif answer == 'y':
   #restart_program???
else:
   print 'Invalid input.'

What I'm trying to do is:

  • if you answer y - the program restarts from the top
  • if you answer n - the program ends (that part works)
  • if you enter anything else, it should print 'invalid input. please enter y or n...' or something, and ask you again for new input.

I got really close to a solution with a "while true" loop, but the program either just restarts no matter what you press (except n), or it quits no matter what you press (except y). Any ideas?

This question is related to python

The answer is


You can do this simply with a function. For example:

def script():
    # program code here...
    restart = raw_input("Would you like to restart this program?")
    if restart == "yes" or restart == "y":
        script()
    if restart == "n" or restart == "no":
        print "Script terminating. Goodbye."
script()

Of course you can change a lot of things here. What is said, what the script will accept as a valid input, the variable and function names. You can simply nest the entire program in a user-defined function (Of course you must give everything inside an extra indent) and have it restart at anytime using this line of code: myfunctionname(). More on this here.


Using one while loop:

In [1]: start = 1
   ...: 
   ...: while True:
   ...:     if start != 1:        
   ...:         do_run = raw_input('Restart?  y/n:')
   ...:         if do_run == 'y':
   ...:             pass
   ...:         elif do_run == 'n':
   ...:             break
   ...:         else: 
   ...:             print 'Invalid input'
   ...:             continue
   ...: 
   ...:     print 'Doing stuff!!!'
   ...: 
   ...:     if start == 1:
   ...:         start = 0
   ...:         
Doing stuff!!!

Restart?  y/n:y
Doing stuff!!!

Restart?  y/n:f
Invalid input

Restart?  y/n:n

In [2]:

I create this program:

import pygame, sys, time, random, easygui

skier_images = ["skier_down.png", "skier_right1.png",
                "skier_right2.png", "skier_left2.png",
                "skier_left1.png"]

class SkierClass(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("skier_down.png")
        self.rect = self.image.get_rect()
        self.rect.center = [320, 100]
        self.angle = 0

    def turn(self, direction):
        self.angle = self.angle + direction
        if self.angle < -2:  self.angle = -2
        if self.angle >  2:  self.angle =  2
        center = self.rect.center
        self.image = pygame.image.load(skier_images[self.angle])
        self.rect = self.image.get_rect()
        self.rect.center = center
        speed = [self.angle, 6 - abs(self.angle) * 2]
        return speed

    def move(self,speed):
        self.rect.centerx = self.rect.centerx + speed[0]
        if self.rect.centerx < 20:  self.rect.centerx = 20
        if self.rect.centerx > 620: self.rect.centerx = 620

class ObstacleClass(pygame.sprite.Sprite):
    def __init__(self,image_file, location, type):
        pygame.sprite.Sprite.__init__(self)
        self.image_file = image_file
        self.image = pygame.image.load(image_file)
        self.location = location
        self.rect = self.image.get_rect()
        self.rect.center = location
        self.type = type
        self.passed = False

    def scroll(self, t_ptr):
        self.rect.centery = self.location[1] - t_ptr

def create_map(start, end):
    obstacles = pygame.sprite.Group()
    gates = pygame.sprite.Group()
    locations = []
    for i in range(10):
        row = random.randint(start, end)
        col = random.randint(0, 9)
        location = [col * 64 + 20, row * 64 + 20]
        if not (location in locations) :
            locations.append(location)
            type = random.choice(["tree", "flag"])
            if type == "tree": img = "skier_tree.png"
            elif type == "flag": img = "skier_flag.png"
            obstacle = ObstacleClass(img, location, type)
            obstacles.add(obstacle)
    return obstacles

def animate():
    screen.fill([255,255,255])
    pygame.display.update(obstacles.draw(screen))
    screen.blit(skier.image, skier.rect)
    screen.blit(score_text, [10,10])
    pygame.display.flip()

def updateObstacleGroup(map0, map1):
    obstacles = pygame.sprite.Group()
    for ob in map0:  obstacles.add(ob)
    for ob in map1:  obstacles.add(ob)
    return obstacles

pygame.init()
screen = pygame.display.set_mode([640,640])
clock = pygame.time.Clock()
skier = SkierClass()
speed = [0, 6]
map_position = 0
points = 0
map0 = create_map(20, 29)
map1 = create_map(10, 19)
activeMap = 0
obstacles = updateObstacleGroup(map0, map1)
font = pygame.font.Font(None, 50)

a = True

while a:
    clock.tick(30)
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                speed = skier.turn(-1)
            elif event.key == pygame.K_RIGHT:
                speed = skier.turn(1)
    skier.move(speed)
    map_position += speed[1]

    if map_position >= 640 and activeMap == 0:
        activeMap = 1
        map0 = create_map(20, 29)
        obstacles = updateObstacleGroup(map0, map1)
    if map_position >=1280 and activeMap == 1:
        activeMap = 0
        for ob in map0:
            ob.location[1] = ob.location[1] - 1280
        map_position = map_position - 1280
        map1 = create_map(10, 19)
        obstacles = updateObstacleGroup(map0, map1)
    for obstacle in obstacles:
        obstacle.scroll(map_position)

    hit = pygame.sprite.spritecollide(skier, obstacles, False)
    if hit:
        if hit[0].type == "tree" and not hit[0].passed:
            skier.image = pygame.image.load("skier_crash.png")
            easygui.msgbox(msg="OOPS!!!")
            choice = easygui.buttonbox("Do you want to play again?", "Play", ("Yes", "No"))
            if choice == "Yes":
                skier = SkierClass()
                speed = [0, 6]
                map_position = 0
                points = 0
                map0 = create_map(20, 29)
                map1 = create_map(10, 19)
                activeMap = 0
                obstacles = updateObstacleGroup(map0, map1)
            elif choice == "No":
                a = False
                quit()
        elif hit[0].type == "flag" and not hit[0].passed:
            points += 10
            obstacles.remove(hit[0])

    score_text = font.render("Score: " + str(points), 1, (0, 0, 0))
    animate()

Link: https://docs.google.com/document/d/1U8JhesA6zFE5cG1Ia3OsTL6dseq0Vwv_vuIr3kqJm4c/edit


This line will unconditionally restart the running program from scratch:

os.execl(sys.executable, sys.executable, *sys.argv)

One of its advantage compared to the remaining suggestions so far is that the program itself will be read again.

This can be useful if, for example, you are modifying its code in another window.


Here's a fun way to do it with a decorator:

def restartable(func):
    def wrapper(*args,**kwargs):
        answer = 'y'
        while answer == 'y':
            func(*args,**kwargs)
            while True:
                answer = raw_input('Restart?  y/n:')
                if answer in ('y','n'):
                    break
                else:
                    print "invalid answer"
    return wrapper

@restartable
def main():
    print "foo"

main()

Ultimately, I think you need 2 while loops. You need one loop bracketing the portion which prompts for the answer so that you can prompt again if the user gives bad input. You need a second which will check that the current answer is 'y' and keep running the code until the answer isn't 'y'.