Categories
Conferences Programming What I’m Up To

I’ll be in the Auth0 booth at PyCon US 2022 this week!

PyCon US 2022, the U.S. edition of the Python conference, happens this week in Salt Lake City, Utah at the Salt Palace Convention Center — and I’m going to be at the Auth0 booth!

Come drop by the booth — we should be pretty easy to find. Just listen for the accordion.

My history with Python

Toronto programmer D’Arcy Cain was looking for a programmer to help him develop an ecommerce site for a client. At the time, the stack that web developers needed to know was LAMP — Linux, Apache, MySQL, and Perl (later expanded to include other languages whose names start with “P”). D’Arcy’s preferred stack was BSD, Apache, Postgres, and Python, which at the time was considered to be a contrarian choice.

He asked if I was willing to learn Python, and I said “Sure! I can pick it up after I get back from Burning Man, on the first day after Labor Day…”

He said “No — I need you to hit the ground running on the first day after Labor Day.”

The edition of Learning Python I used — the first edition!

And I said, “All right. I’ll make it happen.” So I packed my laptop and a copy of O’Reilly’s Learning Python and took it with me to Black Rock Desert.

Those were wild times and even wilder hair, man.

Since Burning Man is more of party-all-night place, it can be quite peaceful in the morning. The rental RV that I shared with San Francisco-based artist David Newman and our friend Nancy was an oasis of calm with a good generator, and I was able to spend a couple of hours a day going through Python exercises, catch a nap, and then strike out onto the playa in the afternoon for the next evening’s mayhem.

By the time I got back to Toronto, I was ready to start coding in Python, and a descendant of that original site and its business still exists today. I figured that any programming language you can learn at Burning Man has to be good, so I’ve been using it to get things done since then, including putting together the Tampa Bay tech events list that appears on this blog weekly.

In spite of my long-time use of Python, even during that period when Ruby was ascendant thanks to Rails, I’ve never gone to PyCon — until now. I’m looking forward to it!

Categories
Meetups Programming Tampa Bay

Building a “Wordle” function, part 1

These slides capture what we worked on Tuesday night’s “Think Like a Coder” meetup: coming up with a first attempt at a “Wordle” function. Given a guess word and a goal word, it should output a Wordle-style score.

We came up with a solution that I like to call the “close enough” algorithm. It goes through the guess word one character at a time, comparing the current guess word character with the goal word character in the same position.

When making those character-by-character comparisons, the function follows the rules:

Here’s the “close enough” algorithm, implemented in Python…

def wordle(guess_word, goal_word):
    
    # Go through the guess word one character at a time, getting...
    # 
    # 1. index: The position of the character
    # 2. character: The character at that position
    for index, character in enumerate(guess_word):
        
        # Compare the current character in the guess word
        # to the goal word character at the same position
        if character == goal_word[index]:
            # Current character in the guess word
            # matches its counterpart in the goal word
            print("green")
        elif character in goal_word:
            # Current character in the guess word
            # DOESN’T match its counterpart in the goal word,
            # but DOES appear in the goal word
            print("yellow")
        else:
            # Current character DOESN’T appear in the goal word
            print("gray")

…and here’s the JavaScript implementation:

function wordle(guessWord, goalWord) {
    
    // Go through the guess word one character at a time
    for (let index in guessWord) {
        // Compare the current character in the guess word
        // to the goal word character at the same position
        if (guessWord[index] == goalWord[index]) {
            // Current character in the guess word
            // matches its counterpart in the goal word
            console.log('green')
        } else if (goalWord.includes(guessWord[index])) {
            // Current character in the guess word
            // DOESN’T match its counterpart in the goal word,
            // but DOES appear in the goal word
            console.log('yellow')
        } else {
            // Current character DOESN’T appear in the goal word
            console.log('gray')
        }
    }
}        

I call the solution “close enough” because yellow is a special case in Wordle. If the guess word is ATOLL and the goal word is ALOFT, the first L in ATOLL should be yellow and the second should be gray because there’s only one L in ALOFT.

We didn’t settle on the “close enough” algorithm — it was just enough for that night’s session. In the next session, we’ll refine the algorithm so that it matches Wordle’s!

Want to become a better programmer? Join us at the next Think Like a Coder meetup!

Categories
Programming Reading Material

Get $411 worth of Python books for $18 with this Humble Bundle!

Once a year, Humble Bundle releases a bundle of No Starch Press’ excellent Python books, and it’s that time of year again! For the next 18 days from the time of this writing, you can get $411 worth of ebooks for as little as $18.

What you get for $1

The bundle is sold in tiers. If you pay only $1, you get this portion of the bundle, which makes for a great starter set for younger readers or if you’re thinking of getting into game development:

If these books alone for a dollar have piqued your interest, you can get them now by going to the Humble Bundle Python book page.

If a dollar is all you can spare, you’ll still be well-served by this deal. However, if you can spend a little more, the deal gets better…

What you get for $10 – $17.99

Pay between $10 and $17.99, and they’ll add these to the bundle:

In my opinion, the stand-out book in this tier is Serious Python, which cover languages features, tools, and techniques that you’ll need as you start writing applications that you or your customers will regularly use and rely upon.

If $17.99 is the most you can spare, you’re still getting a good deal, and you can go to the Humble Bundle Python book page and get your bundle now.

However, if you can part with $18 or more, you should read on…

What you get for $18 or more

And finally, if you pay $18 or more, they’ll throw in the gems of the collection:

If you’re serious about learning Python, you’ll want to pay $18 or more I used Python Crash Course and Automate the Boring Stuff with Python in the Python courses I taught last year.

Even though I bought the 2020 edition of this bundle, I bought the 2021 edition just to get Real World Python is a great way to learn some new tricks through its tour of algorithms and Python libraries. It was cheaper to buy the bundle than to buy Real World Python on its own. Do the math: You can pay $28 for Real World Python, or get all the books in the bundle for $10 less!

Beyond the Basic Stuff with Python is a great guide for writing more Pythonic code, Python One-Liners is worth it for just the NumPy and regex chapters alone, and Natural Language Processing with Python and spaCY packs an NLP course with lots of practical exercises into under 200 pages.

If the $18 bundle is what you’re looking for, go to Humble Bundle and get it while it’s still available!

The money goes to good causes

The proceeds from sales of this bundle go to:

The mission of the Python Software Foundation is to promote, protect, and advance the Python programming language, and to support and facilitate the growth of a diverse and international community of Python programmers. The majority of the PSF’s work is focused on empowering and supporting people within the Python community. The PSF has active grant programs that support sprints, conferences, meetups, user groups, and Python development efforts all over the world. In addition, the PSF underwrites and runs PyCon US, the primary Python community conference. Being part of the PSF means being part of the Python community. Recently we changed the PSF to an open membership organization, so that everyone who uses and supports Python can join.

To learn more, visit https://www.python.org/psf/membership.

The No Starch Press Foundation is an IRS 501 (c) (3) tax-exempt non-profit corporation created to support and grow the collective knowledge and contributions of the worldwide hacker community.

We support hackers of all types, regardless of experience — whether that’s the passionate beginner or the lifelong hacker wishing to make a broader contribution to the hacker community and the world.

The Foundation was formed to give back to and strengthen the hacking community. The Foundation’s founder, William Pollock, has been closely involved with the hacking community since about 1999 and much of the success of his company, No Starch Press, is due to the support of the worldwide hacking community. To date, Pollock has given over $800,000 to the Foundation and is working to expand its donor base. The Foundation’s funding will be used to help strengthen and expand the hacking community, by educating the public about hacking and working to create safe and central places for the hacking community.

Categories
Current Events Programming Tampa Bay

“Python: A Bicycle for the Mind” — 9:00 a.m. this Wednesday at the Women Who Code Tampa online meetup!

I’m talking about Python at this Wednesday’s Women Who Code Tampa online event!

This Wednesday, May 12th, from 9:00 a.m. to 10:00 a.m. Eastern (UTC-4), I’ll be in an online session where I’ll talk about using Python as a “bicycle for the mind”. I’m going to present a couple of Python tricks that I actually use to be more productive.

This session is this week’s installment of Women Who Code Tampa’s Coffee + Code, a weekly online networking event featuring a tech topic.

Here are the relevant links:

What’s this about “Bicycle for the mind”?

It’s how Steve Jobs describes computers in his appearance in a 1990 documentary film called Memory & Imagination: New Pathways to the Library of Congress.

Here’s what he said:

I think one of the things that really separates us from the high primates is that we’re tool builders. I read a study that measured the efficiency of locomotion for various species on the planet.

The condor used the least energy to move a kilometer. And, humans came in with a rather unimpressive showing, about a third of the way down the list. It was not too proud a showing for the crown of creation. So, that didn’t look so good.

But, then somebody at Scientific American had the insight to test the efficiency of locomotion for a man on a bicycle. And, a man on a bicycle, a human on a bicycle, blew the condor away, completely off the top of the charts.

And that’s what a computer is to me. What a computer is to me is it’s the most remarkable tool that we’ve ever come up with, and it’s the equivalent of a bicycle for our minds.

Categories
Programming Reading Material

Humble Bundle’s “Ultimate Python Bookshelf” bundle is available until Monday afternoon!

At the time this article was published, there are 3 days and 21 hours remaining to get Humble Bundle’s “Ultimate Python Bookshelf” bundle. Depending on how much you’re willing to spend, you can get 3, 8, or 24 books at a deeply discounted price, and some of the money goes to two worthy charities. Read on to find out more…

The books

Depending on how much you pay, you’ll get 3, 8 or 24 books.

If you pay $1 – $9.99, you get these books:

  • The Python Workshop
  • The Statistics and Calculus with Python Workshop
  • Web Development with Django

If you pay $10 – $17.99, you get the books above, along with:

  • Hands-on Exploratory Data Analysis with Python
  • Hands-on Machine Learning with scikit-learn and Scientific Python Toolkits
  • Django 3 by Example
  • Python Automation Cookbook
  • Hands-on Genetic Algorithms with Python

And if you pay $18 or more, you get all the books above, plus:

  • Python Data Cleaning Cookbook
  • Deep Reinforcement Learning with Python
  • Data Engineering with Python
  • Modern Python Cookbook
  • Applying Math with Python
  • Python Image Processing Cookbook
  • Python Feature Engineering
  • Practical Python Programming for IoT
  • Python Algorithmic Trading Cookbook
  • Applied Computational Thinking with Python
  • Hands-on Python Natural Language Processing
  • Hands-on Simulation Modeling with Python
  • Mastering Python Networking
  • Artificial Intelligence with Python
  • Python for Finance Cookbook
  • Quantum Computing with Python and IBM Quantum Experience

Interested? You can order the bundle here.

The causes

All Humble Bundles route some of each bundle’s price to one or more charities. In the case of The Ultimate Python Bookshelf bundle, there are two charities that will benefit:

Doctors Without Borders / Médécins Sans Froniteres: An international, independent medical humanitarian organization that delivers emergency aid to people affected by armed conflict, epidemics, natural and man-made disasters, and exclusion from health care in nearly 70 countries.

Stop AAPI Hate: A national coalition addressing anti-Asian racism across the U.S. The coalition was founded by the Asian Pacific Policy and Planning Council (A3PCON), Chinese for Affirmative Action (CAA) and San Francisco State University’s Asian American Studies Department. Between March 19, 2020 and February 28, 2021, Stop AAPI Hate has received 3,795 reported incidents of racism and discrimination targeting Asian Americans across the U.S..

Wait a minute — there are Packt books. Are they worth getting?

As you were reading this article, you were probably wondering about the issue of the less-than-stellar reputation of Packt’s books and if I was going to raise the issue.

Consider the issue raised, Gentle Reader.

When they were starting out, it seemed that Packt took whatever author they could get to write about the hot tech topics of the moment and rushed those books to market. Over the years, the quality of their authors, review process, and books seems to have improved. I know for a fact that Tampa-based iOS developer Craig Clayton has written some excellent books on iOS development for Packt — because I bought them all.

I decided to buy the bundle. I paid the recommended $25 for these reasons:

  • Some of the money goes to two good causes.
  • At $25 for 24 books, that’s less than $1.05 per book.
  • I’m at the point where I won’t even notice a “missing” $25.
  • I don’t consider it $25 spent, but $25 invested.

That last point requires a deeper explanation:

  • If at least a handful of these books are good and provide me with something that I can use at work, in my own programming projects, or in my articles, I will have collected a good return on my investment.
  • Even if most of them are bad, it will still be a worthwhile investment because the 25 books span a wide array of Python topics, and will give me a better idea of what I don’t know, and better still, what I don’t know I don’t know. I can then look for better sources of information.

As I go through each of these books, I’ll post my findings and opinions here.

How to order the bundle

Once again, Humble Bundle’s “Ultimate Python Bookshelf” bundle is available until Monday, April 26 at 2:00 p.m. EDT (UTC-4). If you wanted to learn Python, sharpen your Python skills, or expand your knowledge of where you can apply Python, this bundle is worth considering.

Categories
Programming

Friday 5: Useful things for coders (March 26, 2021 edition)

Every Friday, I publish the Friday 5, a list of 5 links to useful things for coders.

In this week’s Friday 5: a site that catalogs VS Code’s surprising capabilities, a look at the darker corners of Go, background processing in Android, a full-text search in 150 lines of Python, and generating brighter and darker versions of color in JS.

VSCodeCanDoThat.com

Visual Studio Code is a far more capable editor than you might suspect, and the VS Code Can Do That?! can help you discover tips, tricks, and techniques to help you get the most out of this editor.

Each tip/trick/technique comes with a video showing the tip/trick/technique in action and a link to a more detailed description of the tip/trick/technique.

Check it out: VSCodeCanDoThat.com

Darker Corners of Go

The Go (golang) gopher holding a flashlight

Rytis Bieliunas writes:

While simplicity is at the core of Go philosophy you’ll find in further text it nevertheless enables numerous creative ways of shooting yourself in a foot.

Since now I have used Go for production applications for several years and on the account of the many holes in my feet I thought I’d put together a text for the fellow noob students of Go.

My goal is to collect in one place various things in Go that might be surprising to new developers and perhaps shed some light on the more unusual features of Go. I hope that would save the reader lots of Googling and debugging time and possibly prevent some expensive bugs.

Check it out: Darker Corners of Go

Background Processing in Android

Screenshot of Android app doing background processing

Here’s an article from the Auth0 Developer Blog, where I’m one of the writers/editors:

Android apps use the main thread to handle UI updates and operations (like user input). Running long-running operations on the main thread can lead to app freezes, unresponsiveness and thus, poor user experience. To mitigate this, long-running operations should be run in the background. Android has several options for running tasks in the background and in this article, we’ll look at the recommended options for running different types of tasks.

This article uses Java and covers threading, WorkManager, and AlarmManager.

Check it out: Background Processing in Android

Building a full-text search engine in 150 lines of Python code

Flow diagram showing text tokenization

If you’ve wondered how full-text search engines work and thought about building your own, this basic implementation in Python is worth trying out. In this article, you’ll build an engine that searches Wikipedia’s article abstracts and ranks them for relevance, and it’ll do so in milliseconds!

The article covers these major topics:

  • Collecting and formatting the data
  • Indexing the collected data (which includes stemming the words in the data to their basic forms)
  • Searching
  • Ranking results by relevance

Check it out: Building a full-text search engine in 150 lines of Python code

Generate Brighter And Darker Versions Of Color With JavaScript

Chart showing lighter and darker versions of the color redTinyColor is a fantastic JavaScript library that can help you out with a whole bunch of tasks when you’re working with colors. This article takes a quick look at this more-useful-than-you-might-think library.

Check it out: Generate Brighter And Darker Versions Of Color With JavaScript

Are there useful things for coders that should appear in the next edition of Friday 5? Let me know at joey@joeydevilla.com!

Categories
Programming

Code, notes, and recording from the “Programmers of Portables” Meetup, February 22, 2021

What happened at the first Programmers of Portables meetup?

The first Programmers of Portables meetup took place last night, and we made our first steps towards making our first videogame. We met over Zoom, where I shared my screen and led the group in a “code along with me” exercise as we started writing a simple videogame from scratch.

This article covers what we did last night, complete with the code that we wrote. If you were there, you can use this for review. If you weren’t, you should still be able to look at what we did and follow along.

This article is primarily a collection of the code we wrote and the recording of the session. In later articles, I’ll go over Pygame programming in more detail. In the meantime, if you’ve like to learn more about Pygame, here are a couple of resources:

Prerequisites

The first part of the session was devoted to downloading and installing the prerequisites for writing videogames with Python.

A code editor (such as Visual Studio Code)

Logo: Visual Studio Code

Any application that calls itself a code editor will do.

I tend to use Visual Studio Code these days, because I’ve already done my time using earlier versions of vim (in the late ’80s, I used a variant called ivi, short for “improved vi”) and Emacs (back when the joke name was “Eight megs and constant swapping”). VS Code is pretty much the same across all the platforms I use — macOS, Windows, Linux, and Raspberry Pi OS — and it feels like a present-day app, and not leftovers from the 1970s.

You can download Visual Studio Code here.

A distribution of Python 3 (such as Anaconda Python)

Logo: AnacondaWe’re programming in Python (preferably Python 3.7 or later), so any reasonably recent Python distribution will do.

I like the Anaconda Python distribution because iy includes a lot of useful libraries and other tools that you’ll need when using Python for things such as data science, and the experience is pretty much the same across macOS, Windows, and Linux.

You can download Anaconda Python here.

Pygame 2

The final prerequisite is Pygame, a cross-platform set of packages that supports game development in Python. It’s been around for 20 years (its was first release in the fall of 2000), and it’s a fun, fantastic 2D game programming platform.

To install it, you’ll need to go to the command line:

  • macOS and Linux users: Open a terminal and enter the command pip install pygame
  • Windows users using Anaconda Python: Open the Start Menu, select the Anaconda Python folder, and run Anaconda Command Prompt, where you’ll enter the command pip install pygame

The first version: A blank black screen

With the prerequisites gathered and installed on our computers, it was time to start working on the game. We worked on it in steps, each time producing an improved version of the game.

The first version of the game wasn’t terribly impressive, as it ended up being a blank black window that did nothing. Still, it was a working program, and the code we wrote would function as a framework on which we’d eventually build the rest of the game:

Here’s its code:

# The first version of the game:
# An 800-by-600 black window
# (Don’t worry; it gets better)

import pygame

# Constants
# =========

# Screen dimensions and refresh rate
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FRAMES_PER_SECOND = 60

# Colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)


# Initialization
# ==============
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()


# Game loop
# =========
running = True

while running:
    # This method should be called once per frame.
    # It calculates the number of milliseconds since the last
    # call to clock.tick() in order to limit the game’s framerate
    # to a maximum of FRAMES_PER_SECOND.
    clock.tick(FRAMES_PER_SECOND)

    # Handle events
    for event in pygame.event.get():
        # Check to see if the user has closed the window
        # or hit control-c on the command line
        # (i.e. Has the user quit the program?)
        if event.type == pygame.QUIT:
            running = False

    # Draw game objects to the screen surface
    screen.fill(BLACK)

    # Update the screen with the contents of the screen surface
    pygame.display.flip()

# Exit the game
pygame.quit()

The second version: A rightward-moving green square

The second version of the game built upon the code from the first, and was slightly more impressive. It featured an actual image on the screen, complete with animation: a green square, travelling from left to right across the screen, and “wrapping around” back to the left side after it disappears from the right side of the screen.

Here’s its code:

# The second version of the game:
# An 800-by-600 black window,
# now with a rightward-moving green square!

import pygame

# Constants
# =========

# Screen dimensions and refresh rate
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FRAMES_PER_SECOND = 60

# Colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)


# Sprites
# =======

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50, 50))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.center = (SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)

    def update(self):
        self.rect.x = self.rect.x + 5
        if self.rect.left > SCREEN_WIDTH:
            self.rect.right = 0


# Initialization
# ==============

# Initialize screen and framerate
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()

# Create sprites and sprite groups
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)


# Game loop
# =========
running = True

while running:
    # This method should be called once per frame.
    # It calculates the number of milliseconds since the last
    # call to clock.tick() in order to limit the game’s framerate
    # to a maximum of FRAMES_PER_SECOND.
    clock.tick(FRAMES_PER_SECOND)

    # Handle events
    for event in pygame.event.get():
        # Check to see if the user has closed the window
        # or hit control-c on the command line
        # (i.e. Has the user quit the program?)
        if event.type == pygame.QUIT:
            running = False

    # Update the game state
    all_sprites.update()

    # Draw game objects to the screen surface
    screen.fill(BLACK)
    all_sprites.draw(screen)

    # Update the screen with the contents of the screen surface
    pygame.display.flip()

# Exit the game
pygame.quit()

The third version: The green square, now under user control!

The final version of the game was one where we made the green square interactive. Instead of continuously travelling from left to right on the screen, the square stays put until the user presses one of the arrow keys. When that happens, the square moves in the appropriate direction. The square is constrained so that it can’t go offscreen.

Here’s its code:

# The third version of the game:
# The green square, now under user control!

import pygame

# Constants
# =========

# Screen dimensions and refresh rate
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FRAMES_PER_SECOND = 60

# Colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)


# Sprites
# =======

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50, 50))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.center = (SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)

    def update(self):
        # Get the state of all the keys
        keys = pygame.key.get_pressed()

        # Check the retrieved state to see if any
        # arrow keys have been pressed
        # =======================================

        # Is the user pressing the left-arrow key,
        # and is the sprite’s left edge NOT flush
        # with the screen’s left edge?
        if keys[pygame.K_LEFT] and self.rect.x > 0:
            self.rect.x = self.rect.x - 5

        # Is the user pressing the right-arrow key,
        # and is the sprite’s right edge NOT FLUSH
        # with the screen’s right edge?
        if keys[pygame.K_RIGHT] and self.rect.x < SCREEN_WIDTH - self.rect.width:
            self.rect.x = self.rect.x + 5

        # Is the user pressing the up-arrow key,
        # and is the sprite’s top edge NOT FLUSH
        # with the screen’s top edge?
        if keys[pygame.K_UP] and self.rect.y > 0:
            self.rect.y = self.rect.y - 5

        # Is the user pressing the down-arrow key,
        # and is the sprite’s bottom edge NOT FLUSH
        # with the screen’s bottom edge?
        if keys[pygame.K_DOWN] and self.rect.y < SCREEN_HEIGHT - self.rect.height:
            self.rect.y = self.rect.y + 5


# Initialization
# ==============

# Initialize screen and framerate
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()

# Create sprites and sprite groups
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)


# Game loop
# =========
running = True

while running:
    # This method should be called once per frame.
    # It calculates the number of milliseconds since the last
    # call to clock.tick() in order to limit the game’s framerate
    # to a maximum of FRAMES_PER_SECOND.
    clock.tick(FRAMES_PER_SECOND)

    # Handle events
    for event in pygame.event.get():
        # Check to see if the user has closed the window
        # or hit control-c on the command line
        # (i.e. Has the user quit the program?)
        if event.type == pygame.QUIT:
            running = False

    # Update the game state
    all_sprites.update()

    # Draw game objects to the screen surface
    screen.fill(BLACK)
    all_sprites.draw(screen)

    # Update the screen with the contents of the screen surface
    pygame.display.flip()

# Exit the game
pygame.quit()

The recording

Here’s the recording of the session: