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:

Categories
Programming

On the Auth0 blog: How to read, edit, and erase location and other EXIF metadata from your photos

Auth0 logoMy latest article on the Auth0 blog, How to Read and Remove Metadata from Your Photos With Python, shows you how to use Python and the exif module to examine, alter, and even remove the metadata that your phone adds to pictures you take.

In addition to picture data, photos taken with smartphones and modern digital cameras contain metadata, which is additional information about the photo. This metadata is stored in a format called EXIF, which is short for EXchangeable Image File format, which is a continually evolving standard for information added to digital image and sound recordings.

In photos, EXIF can include information such as:

  • The dimensions and pixel density of the photo
  • The make and model of the device used to take the photo
  • Zoom, aperture, flash, and other camera settings when the photo was taken
  • The orientation of the device when the photo was taken
  • When the photo was taken
  • Where the photo was taken
  • Which direction the camera was facing
  • The altitude at which the photo was taken

My article will show you how to use Python’s exif module to access this information, as well as how to alter it (I show you how to tag your photos so it seems as if they were taken at Area 51) or erase it.

EXIF data was recently in the spotlight as a result of the January 6th riots in Washington, DC. Many of the rioters posted photos to Parler, which did not strip EXIF data from photos uploaded to it.

When Parler started to shut down as a result of Amazon and other providers kicking them off their services, it opened some security holes that a hacktivist who goes by the handle @donk_enby was able to exploit. They were able to scrape the posts and uploaded photos and videos and upload them to the Internet Archive. Soon after, it was discovered that Parler never removed the EXIF data from the photos and videos, which made it possible to easily identify participants in the riot, see who broke into the Capitol, and for authorities to make arrests. The New York Times used this data to make a timeline of events, which they published in their article, How a Presidential Rally Turned Into a Capitol Rampage.

Graphic from the New York Times. Tap to view at full size.

While Parler’s sloppy security was by and large good news, there’s still good reason to follow good security practices, and part of that is managing EXIF data in photographs. That’s what my article covers, and in a fun way as well!

Read the article on the Auth0 blog: How to Read and Remove Metadata from Your Photos With Python.

 

Categories
Programming What I’m Up To

My solution to Advent of Code 2020’s Day 8 challenge, in Python

Welcome to another installment in my Advent of Code 2020 series, where I present my solutions to this year’s Advent of Code challenges!

In this installment, I share my Python solution to Day 8 of Advent of Code, titled Handheld Halting.

Spoiler alert!

Please be warned: If you want to try solving the challenge on your own and without any help, stop reading now! The remainder of this post will be all about my solution to both parts of the Day 8 challenge.

The Day 8 challenge, part one

The Kittenbot Meowbit handheld game console. Tap to find out more.

The challenge

Here’s the text from part one of the challenge:

Your flight to the major airline hub reaches cruising altitude without incident. While you consider checking the in-flight menu for one of those drinks that come with a little umbrella, you are interrupted by the kid sitting next to you.

Their handheld game console won’t turn on! They ask if you can take a look.

You narrow the problem down to a strange infinite loop in the boot code (your puzzle input) of the device. You should be able to fix it, but first you need to be able to run the code in isolation.

The boot code is represented as a text file with one instruction per line of text. Each instruction consists of an operation (accjmp, or nop) and an argument (a signed number like +4 or -20).

  • acc increases or decreases a single global value called the accumulator by the value given in the argument. For example, acc +7 would increase the accumulator by 7. The accumulator starts at 0. After an acc instruction, the instruction immediately below it is executed next.
  • jmp jumps to a new instruction relative to itself. The next instruction to execute is found using the argument as an offset from the jmp instruction; for example, jmp +2 would skip the next instruction, jmp +1 would continue to the instruction immediately below it, and jmp -20 would cause the instruction 20 lines above to be executed next.
  • nop stands for No OPeration – it does nothing. The instruction immediately below it is executed next.

For example, consider the following program:

nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6

These instructions are visited in this order:

nop +0  | 1
acc +1  | 2, 8(!)
jmp +4  | 3
acc +3  | 6
jmp -3  | 7
acc -99 |
acc +1  | 4
jmp -4  | 5
acc +6  |

First, the nop +0 does nothing. Then, the accumulator is increased from 0 to 1 (acc +1) and jmp +4 sets the next instruction to the other acc +1 near the bottom. After it increases the accumulator from 1 to 2, jmp -4 executes, setting the next instruction to the only acc +3. It sets the accumulator to 5, and jmp -3 causes the program to continue back at the first acc +1.

This is an infinite loop: with this sequence of jumps, the program will run forever. The moment the program tries to run any instruction a second time, you know it will never terminate.

Immediately before the program would run an instruction a second time, the value in the accumulator is 5.

Run your copy of the boot code. Immediately before any instruction is executed a second time, what value is in the accumulator?

Importing the data

Every Advent of Code participant gets their own set of data. I copied my data and went through my usual process of bringing it into a Jupyter Notebook running a Python kernel.

This involves pasting it into a triple-quoted string and then assigning its value to the variable main_raw_input:

main_raw_input = """acc +37
acc -4
nop +405
jmp +276
acc +39
acc +40
acc -3
jmp +231
acc +44
acc +12
jmp +505
acc +35
jmp +282
acc +23
jmp +598
nop +392
acc +18
acc +44
acc +18
jmp +297
nop +460
jmp +152
nop +541
acc +33
jmp -11
acc -5
acc +9
jmp +327
acc +30
acc -1
acc -3
jmp +50
acc +22
acc +18
acc +33
acc +37
jmp +57
acc -17
acc -6
acc -2
jmp +535
acc -15
jmp +279
acc +34
acc +44
acc +41
jmp +349
acc +2
acc +6
nop +351
nop +252
jmp +505
jmp +1
jmp +1
nop +61
jmp +524
nop +351
jmp +399
acc +1
nop +397
acc +39
nop +141
jmp +134
acc +46
acc +14
acc +26
jmp +236
acc +7
acc -6
acc +35
jmp +397
acc +15
jmp +140
acc +3
acc -4
acc +37
acc +12
jmp +86
jmp +416
jmp +1
jmp +55
acc -19
jmp +536
jmp +1
acc -11
acc +15
jmp -61
acc +25
jmp -25
acc +50
acc +43
jmp +1
jmp +140
acc +46
nop -53
acc +1
nop +440
jmp +488
jmp +396
nop +443
acc +41
jmp +168
acc +25
nop +383
acc +12
acc -19
jmp +21
acc +29
acc +30
jmp +497
jmp +502
jmp +417
nop +351
acc -15
jmp +243
acc +21
acc +16
jmp +332
acc +28
acc +22
acc +38
jmp +476
acc +8
acc -11
jmp +458
acc +9
jmp +246
acc +40
acc +31
acc +26
jmp +218
acc +27
acc +9
nop +347
jmp +478
nop +28
nop +106
acc +25
acc -15
jmp +397
acc +31
jmp +231
acc -4
nop +136
acc +14
jmp +181
jmp +361
acc +16
acc +11
jmp -108
nop +299
acc +21
acc -2
jmp -106
jmp +246
acc +31
jmp +407
jmp +377
acc +43
acc -12
nop +142
acc +8
jmp -91
jmp +1
acc +34
acc +5
acc +31
jmp +12
acc +34
acc +7
acc +34
acc +20
jmp -45
acc -11
acc +41
acc +10
jmp +310
nop -106
jmp -36
acc +23
acc +46
acc +46
jmp +112
acc +41
nop +179
acc +17
nop +356
jmp +147
acc +42
nop +49
jmp +119
acc +0
acc +7
acc -18
acc -8
jmp +11
acc +12
acc +38
acc +39
jmp +281
nop +186
jmp +162
acc +44
acc +20
jmp +153
jmp +395
acc +49
jmp +1
acc +2
jmp +1
jmp -31
jmp +301
nop +97
jmp -102
jmp +262
acc +28
acc -15
acc +44
acc -13
jmp +191
jmp +281
acc +36
acc +1
nop +15
jmp +211
acc +6
acc -4
jmp +42
acc +34
acc +0
jmp +104
jmp +311
jmp +84
acc +43
acc -8
acc -10
acc +38
jmp -90
acc +49
jmp +303
nop +132
jmp +301
nop +60
acc +37
nop +96
jmp +182
acc +16
acc +18
nop +152
acc +19
jmp +325
jmp -63
acc +28
jmp +56
acc +18
acc +29
acc +33
jmp -115
acc +47
acc +19
jmp +1
nop +41
jmp +1
jmp -207
nop -62
acc -9
acc +42
acc -12
jmp -56
acc +28
jmp -163
acc +25
acc +17
jmp -217
acc +7
jmp +272
acc +43
acc +22
jmp +70
acc -17
jmp -117
acc +24
acc +26
nop -275
jmp -46
nop +87
acc +19
acc +28
jmp -34
acc +4
acc +9
acc +6
jmp +1
jmp +28
acc -6
nop -67
acc -10
jmp +271
acc +40
acc +25
acc -4
jmp -63
acc +46
jmp +78
acc +41
nop -126
nop +70
jmp +1
jmp +172
nop +270
jmp +30
jmp +1
acc +38
nop +68
acc +29
jmp +253
acc -18
jmp -89
acc +18
acc +30
jmp +147
acc +24
acc +11
acc +50
jmp -225
jmp -210
acc -18
acc +1
acc +38
jmp +1
jmp -79
acc +45
acc +12
jmp +209
jmp -207
acc +32
acc +4
acc +32
acc +14
jmp +83
acc +13
acc +1
acc +46
acc +38
jmp +28
nop +153
acc -17
jmp -73
acc +11
jmp +248
acc +29
acc +45
acc +16
jmp +96
jmp -273
acc +34
jmp +87
nop +99
acc -3
jmp -74
acc +12
nop -119
jmp -141
acc -18
nop -79
acc +1
acc +6
jmp +9
acc +3
acc +44
acc +39
jmp -165
acc +6
jmp +44
acc +25
jmp -133
acc +0
jmp +14
jmp +1
acc +1
jmp -223
jmp +71
nop -1
acc +22
acc +11
jmp -274
jmp -330
acc +45
jmp +1
acc +15
jmp -158
jmp -128
acc +50
acc +26
jmp -73
nop +99
jmp +71
acc +35
acc +7
jmp +192
acc +13
jmp +190
acc +4
acc -1
acc +40
acc -15
jmp +50
acc +29
jmp -337
jmp -75
acc +41
jmp +1
jmp -387
acc +28
acc +18
acc +19
jmp -62
nop -196
jmp -410
jmp +1
acc -17
jmp -267
acc +22
jmp -301
nop -98
acc -15
jmp -124
acc +45
acc -18
acc +15
acc +42
jmp -296
nop -10
acc +29
jmp -371
acc +3
jmp +1
nop +61
acc +5
jmp -361
acc -5
nop -326
jmp -379
acc -10
jmp +1
acc +44
jmp -231
acc +3
jmp -94
acc +1
jmp +113
jmp -336
acc +4
jmp -299
acc -13
jmp +1
acc +13
jmp +143
acc -11
acc -19
acc +18
nop -390
jmp -27
acc +42
jmp -232
acc +15
jmp -228
acc +21
acc +39
acc +47
acc +6
jmp +57
acc +28
acc +27
acc +50
jmp -397
acc +12
jmp -445
acc +30
jmp -352
acc -4
acc +26
acc +48
jmp +1
jmp -205
jmp +22
nop -284
acc -1
nop -361
acc +0
jmp -368
acc -17
nop -223
jmp -41
acc +4
acc +46
jmp +79
jmp -370
jmp -260
acc +42
jmp -14
acc +30
acc +50
acc +13
jmp -61
acc +46
jmp -63
nop -55
nop -320
jmp -11
acc +10
jmp -424
jmp -11
acc +3
jmp -71
acc +42
acc -13
jmp +4
nop -155
nop -138
jmp +62
acc +11
acc +19
acc +15
acc +17
jmp -73
acc -11
jmp -273
acc +8
acc +6
acc -7
acc +41
jmp -311
jmp -111
jmp -260
jmp +50
jmp -60
jmp +1
nop -89
acc +36
acc +14
jmp -220
nop -415
acc +28
jmp -402
acc +41
jmp -165
acc +9
acc -13
acc -18
acc +18
jmp -504
acc -9
acc +29
acc +44
jmp -444
acc +5
acc +47
jmp -545
acc +23
acc +7
nop -240
jmp -320
jmp -141
jmp +1
acc +28
nop -287
jmp -118
acc +44
acc -7
jmp -550
acc +10
acc +20
acc -3
jmp -401
acc +45
acc +36
jmp -375
jmp -485
acc +9
jmp -338
jmp -510
jmp -196
acc -16
jmp -372
acc +0
jmp -380
acc -3
nop -473
nop -361
jmp -311
acc +0
nop +20
jmp -436
acc +9
jmp +1
jmp -215
acc +19
jmp -451
jmp -43
acc -13
acc -10
acc -5
jmp -208
acc -11
jmp -156
acc +11
acc -2
nop -357
jmp -73
acc +21
jmp -159
acc +28
acc -16
acc +12
acc +1
jmp -282
jmp -131
acc -11
acc +45
acc +0
acc +28
jmp +1"""

Building the data structure

With the data imported, the next step was to build an appropriate data structure. Since today’s puzzle was based on simplified microprocessor instructions, I thought that the data structure should do the same.

I wanted my data structure to look like the table below, which shows the instructions from extracted from the first five lines of the data given to me:

Index Opcode Operand
0 acc 37
1 acc -4
2 nop 405
3 jmp 276
4 acc 39

Here’s the function that I wrote to convert the input data into the data structure:

def input_to_instructions(input_data):
    instructions = []
    
    split_input = input_data.splitlines()
    
    for item in split_input:
        instruction = {}
        opcode_operand = item.split()
        instruction["opcode"] = opcode_operand[0]
        instruction["operand"] = int(opcode_operand[1])
        instructions.append(instruction)
        
    return instructions

With the function defined, here’s how I used it to create the data structure, which I assigned to a variable named instructions:

>>> instructions = input_to_instructions(main_raw_input)
>>> print (instructions)

[{'opcode': 'acc', 'operand': 37},
 {'opcode': 'acc', 'operand': -4},
 {'opcode': 'nop', 'operand': 405},
 {'opcode': 'jmp', 'operand': 276},
 {'opcode': 'acc', 'operand': 39},

...

]

I then wrote accumulator_value_at_first_repeat(), the function that would use the data structure contained within instructions to solve the first challenge:

def accumulator_value_at_first_repeat(instructions):
    program_length = len(instructions)
    program_counter = 0
    accumulator = 0
    executed_instructions = set()
    repeat_instruction_encountered = False
    
    while 0 <= program_counter < program_length:
        current_instruction = instructions[program_counter]
        
        if program_counter in executed_instructions:
            repeat_instruction_encountered = True
            break
        else:
            executed_instructions.add(program_counter)
            
        if current_instruction["opcode"] == "jmp":
            program_counter += current_instruction["operand"]
            continue
        elif current_instruction["opcode"] == "acc":
            accumulator += current_instruction["operand"]
        elif current_instruction["opcode"] == "nop":
            pass
        else:
            print("Something went wrong in accumulator_value_at_first_repeated_instruction().")
            print(f"pc = {program_counter} acc = {accumulator}")
            print(f"instruction:\n{instruction}")
            
        program_counter += 1
    
    if repeat_instruction_encountered:
        print(f"The accumulator's contents at the first repeated instruction is: {accumulator}.")
    else:
        print("Reached end of instructions without repeating any of them.")

When run, it sets up the following variables:

  • program_length: The number of instructions in the data structure.
  • program_counter: The program’s equivalent of the “program counter (PC)” register in a microprocessor; contains the index the instruction to be executed.
  • accumulator: The program’s equivalent of an accumulator in a microprocessor. For those of you who aren’t familiar with what happens at the microprocessor level, think of the accumulator as a “scratchpad” variable where you do all the math.
  • executed_instructions: A set (which means that every value in it is unique) of the indices of all the instructions that have already been executed. We use it to determine if a given instruction has already been run, at which point we should stop the program and see what the value in the accumulator is.
  • repeat_instruction_encountered: A flag that should be set to True when an instruction is about to be executed a second time.

The function’s main loop performs a greatly simplified version of a microprocessor’s “fetch-decode-execute” cycle:

  1. Fetch the current instruction, which is the one whose index is specified by program_counter.
  2. See if the instruction has been executed before. If this is the case, exit the loop; otherwise, recording this instruction as having been executed.
  3. Decode the current instruction:
    • If the instruction is jmp, add the operand value to program_counter and go back to the start of the loop.
    • If the instruction is acc, add the operand value to accumulator.
    • If the instruction is nop, do nothing.
    • If the instruction is anything else, display an error message.
  4. After the loop is done, if the repeat_instruction_encountered flag is set, we’ve found the value we’re looking for — display it! Otherwise, display a message saying that we’ve reached the end of the instructions without ever repeating one.

I ran the function…

>>> accumulator_value_at_first_repeat(instructions)

The accumulator's contents at the first repeated instruction is: 1801.

…and got my result: 1801.

The Day 8 challenge, part two

The TinkerGen GameGo programmable handheld game console. Tap to find out more!

The challenge

After some careful analysis, you believe that exactly one instruction is corrupted.

Somewhere in the program, either a jmp is supposed to be a nopor a nop is supposed to be a jmp. (No acc instructions were harmed in the corruption of this boot code.)

The program is supposed to terminate by attempting to execute an instruction immediately after the last instruction in the file. By changing exactly one jmp or nop, you can repair the boot code and make it terminate correctly.

For example, consider the same program from above:

nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6

If you change the first instruction from nop +0 to jmp +0, it would create a single-instruction infinite loop, never leaving that instruction. If you change almost any of the jmp instructions, the program will still eventually find another jmp instruction and loop forever.

However, if you change the second-to-last instruction (from jmp -4 to nop -4), the program terminates! The instructions are visited in this order:

nop +0  | 1
acc +1  | 2
jmp +4  | 3
acc +3  |
jmp -3  |
acc -99 |
acc +1  | 4
nop -4  | 5
acc +6  | 6

After the last instruction (acc +6), the program terminates by attempting to run the instruction below the last instruction in the file. With this change, after the program terminates, the accumulator contains the value 8 (acc +1acc +1acc +6).

Fix the program so that it terminates normally by changing exactly one jmp (to nop) or nop (to jmp). What is the value of the accumulator after the program terminates?

Here’s the function I wrote to solve this challenge:

def accumulator_value_and_halt_at_first_repeat(instructions, switch_opcode_address=-1):
    program_length = len(instructions)
    program_counter = 0
    accumulator = 0
    executed_instructions = set()
    
    while 0 <= program_counter < program_length:
        current_instruction = instructions[program_counter]
        
        if program_counter in executed_instructions:
            return {
                "halted": False,
                "program_counter": program_counter,
                "accumulator": accumulator
            }
        else:
            executed_instructions.add(program_counter)
            
        opcode = current_instruction["opcode"]
        operand = current_instruction["operand"]
            
        if program_counter == switch_opcode_address:
            print(f"Changing opcode at address {program_counter}")
            if opcode == "jmp":
                print("- Changing jmp to nop")
                opcode = "nop"
            elif opcode == "nop":
                print("- Changing nop to jmp")
                opcode = "jmp"
            
        if opcode == "jmp":
            program_counter += operand
            continue
        elif opcode == "acc":
            accumulator += operand
        elif opcode == "nop":
            pass
        else:
            print("Something went wrong in accumulator_value_at_first_repeated_instruction().")
            print(f"pc = {program_counter} acc = {accumulator}")
            print(f"instruction:\n{instruction}")
            
        program_counter += 1
            
    return {
                "halted": True,
                "program_counter": program_counter,
                "accumulator": accumulator
            }

The function, accumulator_value_and_halt_at_first_repeat(), is an expanded version of the function from part one, accumulator_value_at_first_repeat().

In addition to a set of instructions, it takes an additional parameter: the address of an instruction that should be changed — either from jmp to nop, or from nop to jmp.

The function still performs the “fetch-decode-execute” loop, and it exits the loop if it’s about to execute an instruction that’s already been executed. The main difference is that if the current instruction is the one flagged for change, it changes the instruction appropriately.

I wrote the accumulator_value_and_halt_at_first_repeat() function to be used by the function below:

def run_instructions_with_mods(program):
    
    for index in range(len(program)):
        instruction = program[index]
        if instruction["opcode"] != "acc":
            print(f"Found jmp or nop at address: {index}")
            result = accumulator_value_and_halt_at_first_repeat(program, index)
            if result["halted"]:
                print(f"Found it! {result}")
                break
            else:
                print(f"Not the correct instruction.")

This function goes through all the instructions in the set, looking for any jmp or nop instructions. When it finds one, it runs the program using accumulator_value_and_halt_at_first_repeat(), marking the jmp or nop instruction as the one to be changed.

This lets us modify the program, one jmp or nop instruction at a time, in order to find which change to a jmp or nop instruction is the one that allows the program to reach the end of the instructions.

Here’s an abridged version of what happened when I ran the function:

>>> run_instructions_with_mods(instructions)

Found jmp or nop at address: 2
Changing opcode at address 2
- Changing nop to jmp
Not the correct instruction.
Found jmp or nop at address: 3
Changing opcode at address 3
- Changing jmp to nop
Not the correct instruction.
Found jmp or nop at address: 7
Not the correct instruction.
Found jmp or nop at address: 10
Changing opcode at address 10
- Changing jmp to nop
Not the correct instruction.

...


Found jmp or nop at address: 207
Changing opcode at address 207
- Changing jmp to nop
Not the correct instruction.
Found jmp or nop at address: 209
Changing opcode at address 209
- Changing jmp to nop
Not the correct instruction.
Found jmp or nop at address: 210
Changing opcode at address 210
- Changing jmp to nop
Found it! {'halted': True, 'program_counter': 623, 'accumulator': 2060}

I entered 2060 as my answer, and step two was complete.

Solutions for other days in Advent of Code 2020