← Deeper Python in the console

Save the game

Write the game to a file with json, read it back next time, and catch the error when there is no file yet.

Every game that lets you carry on tomorrow writes its world to a file, and reads it back when you return.

Your adventure forgets everything when the program stops. To carry on later, a program writes what it needs to a file, and reads it back next time. This lesson's playground keeps files in your browser, like files on a computer: they are still there after you close the page. The Files tab shows them.

PredictRead the code and say what it will do before you run anything. A wrong guess is fine: it shows you what to look for.

Predict

save.py
with open("note.txt", "w") as f:
    f.write("kitchen")
with open("note.txt", "w") as f:
    f.write("garden")
with open("note.txt") as f:
    print(f.read())

open("note.txt", "w") opens a file for writing; open("note.txt") opens it for reading. The file is written twice, then read. What is in it at the end?

What does it print?

RunRun it and compare the result with your prediction.

Run

Run it, type your name, then run it again, and again. Reload the page and run it once more. Then open the Files tab and look inside me.json. Delete the file there, and run it again.

save.py
import json

try:
    with open("me.json") as f:
        me = json.load(f)
    me["visits"] = me["visits"] + 1
    print("Welcome back, " + me["name"] + ". This is visit " + str(me["visits"]) + ".")
except FileNotFoundError:
    name = input("What is your name? ")
    me = {"name": name, "visits": 1}
    print("Nice to meet you, " + name + ". Run me again.")

with open("me.json", "w") as f:
    json.dump(me, f)
Try it yourselfYour edits are saved in this browser.

InvestigateTrace how each line of code connects to what you see.

Investigate

save.py
import json

try:
    with open("me.json") as f:
        me = json.load(f)
    me["visits"] = me["visits"] + 1
    print("Welcome back, " + me["name"] + ". This is visit " + str(me["visits"]) + ".")
except FileNotFoundError:
    name = input("What is your name? ")
    me = {"name": name, "visits": 1}
    print("Nice to meet you, " + name + ". Run me again.")

with open("me.json", "w") as f:
    json.dump(me, f)

Where the program goes when there is no file.

What json.dump wrote. Look in the Files tab to check.

What json.load gives you.

A program that wipes its own save.

The very first time it runs, why does the except part run?

What does me.json hold after Ada's second run?

After me = json.load(f), what is me?

This should welcome Ada back, but it stops with an error, and afterwards me.json is empty. Click the line that is wrong.

ModifyChange the code on purpose and check the result.

Milestone 1: save

This is the adventure from the last lesson, with import json at the top. Where the comment says Milestone 1, add a save command:

  1. Put everything that changes during play in one dictionary: game = {"here": here, "bag": bag, "things": things}.
  2. Open game.json with "w" and json.dump(game, f), then print Saved.

Test: take the lamp, save, then look in the Files tab.

Try it yourselfYour edits are saved in this browser.

save writes here, bag and things to game.json with json.dump.

    Run your program. This ticks when your code does all of the above.

    ModifyChange the code on purpose and check the result.

    Milestone 2: load

    save works in this version. Where the comment says Milestone 2, add a load command: open game.json, game = json.load(f), then set here, bag and things from game, and print the room. If there is no file yet, catch FileNotFoundError and say there is no saved game.

    Test it properly: take something, save, quit, reload the page, run again, load, bag.

    Try it yourselfYour edits are saved in this browser.

    load reads game.json with json.load and sets here, bag and things, and says so if there is no save yet.

      Run your program. This ticks when your code does all of the above.

      MakeBuild something new using what you have learned. Expect a few tries; that is normal.

      Carry on where you left off

      When the game starts and there is a save, ask whether to load it. With no save, start a new game.

      Need a hint?

      Before the loop, try to open game.json. If it is there, ask whether to load it.

      Another hint

      except FileNotFoundError: is a new game, so just print the first room.

      Some ideas: save automatically when the player types quit; count the moves and save them too; keep the best (fewest) moves in a second file.

      Try it yourselfYour edits are saved in this browser.

      Info

      Where this leads

      Files are how programs remember: games save progress, apps keep settings, and data is shared as files (JSON, and the CSV tables in Data detective). The same open(), json.dump and json.load work in Python on any computer; there the files go in the folder the program runs in.

      A friend opens your game on their own computer. Will your saved game be there?

      For teachers

      Students write and read a file, save a dictionary with json, catch FileNotFoundError for a first run, then add save and load commands to their text adventure and test that a save survives a page reload. About 50 minutes.

      Open the teacher guide: answers, solutions, slides and a worksheet.

      Students will be able to

      Before class

      Read the unit primer first. This lesson runs in the Python playground (real Python in the browser, Pyodide), not the turtle playground: it has real files. The first load takes a few seconds; before teaching it, open the site's Check your school page once on a student device at school. A student's files are kept in their browser for this course and listed in the Files tab, where they can be read and deleted; they survive closing the page, but not clearing the browser's data, and they do not follow a student to another device. open(name, "w") empties the file first (the Predict and the bug task); open(name) reads. with closes the file when its block ends. json.dump(data, f) writes a dictionary or list as JSON text, and json.load(f) gives the same dictionary back. Opening a missing file causes FileNotFoundError, caught exactly like the errors in Lesson 4. The game saves here, bag and things (everything that changes during play): saving only here and bag would let a player take the key twice.

      Running the lesson

      1. Predict: write kitchen then garden on two sticky notes; the second "w" throws the first note away.
      2. Run: have students reload the page between runs. The point is that the file outlives the program.
      3. Investigate: open the Files tab and compare me.json with the dictionary in the code.
      4. Milestone 1: ask what changes during play. Everything that changes must be saved.
      5. Milestone 2: test with a reload, not just a second command. Pair students: one saves, the other reloads and loads.

      The hard part (on purpose)

      Milestone 2 is the hard part: putting the loaded values back into here, bag and things. When students are stuck, ask them to say aloud what game holds after json.load, before giving any code.

      When students get stuck

      Stretch and support

      Stretch: Keep a best score in a second file (fewest moves to win), and only replace it when a new game beats it.

      Support: Give students the save branch written out and ask them to write load by mirroring it, with json.load instead of json.dump.

      Where it leads

      Data detective reads data files (CSV and JSON) the same way. Web apps later store what users type in a file, then in a database.

      What each step is for

      Now you can
      You reached the endBack to Deeper Python in the console