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 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 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 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:

These instructions are visited in this order:

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:

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:

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

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

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…

…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:

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:

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:

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:

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:

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

Solutions for other days in Advent of Code 2020

Categories
Programming What I’m Up To

My solution to Advent of Code 2020’s Day 6 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 6 of Advent of Code, titled Custom Customs.

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 6 challenge.

The Day 6 challenge, part one

The challenge

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

As your flight approaches the regional airport where you’ll switch to a much larger plane, customs declaration forms are distributed to the passengers.

The form asks a series of 26 yes-or-no questions marked a through z. All you need to do is identify the questions for which anyone in your group answers “yes”. Since your group is just you, this doesn’t take very long.

However, the person sitting next to you seems to be experiencing a language barrier and asks if you can help. For each of the people in their group, you write down the questions for which they answer “yes”, one per line. For example:

In this group, there are 6 questions to which anyone answered “yes”: abcxy, and z. (Duplicate answers to the same question don’t count extra; each question counts at most once.)

Another group asks for your help, then another, and eventually you’ve collected answers from every group on the plane (your puzzle input). Each group’s answers are separated by a blank line, and within each group, each person’s answers are on a single line. For example:

This list represents answers from five groups:

  • The first group contains one person who answered “yes” to 3 questions: ab, and c.
  • The second group contains three people; combined, they answered “yes” to 3 questions: ab, and c.
  • The third group contains two people; combined, they answered “yes” to 3 questions: ab, and c.
  • The fourth group contains four people; combined, they answered “yes” to only 1 question, a.
  • The last group contains one person who answered “yes” to only 1 question, b.

In this example, the sum of these counts is 3 + 3 + 3 + 1 + 1 = 11.

For each group, count the number of questions to which anyone answered “yes”. What is the sum of those counts?

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 assigning it to the variable raw_input, and then splitting it using two newline characters in a row as a delimiter, producing a list named split_input:

Each item in the split_input list represents the collected answers for a group. If a group has more than one person in it, a newline character separates each person’s answers.

In the sample of split_input shown below:

  • The first line shows the answers for the first group, which is made up of two people.
  • The fifth line shows the answers for the fifth group, which is made up of five people. All of them answered yes to only one question: Question v.

Finally, I split each item in split_items, using the newline character as the separator:

The result was a list that I named groups, where:

  • Each item in groups represents a group of passengers
  • Each group is a list, where each item in the list represents the answers for one passenger in that group.

Here’s a sample of groups:

With the input data massaged into something that could easily be processed in Python, it was time to get to work.

Strategy

The goal was to get the total of all the “yes” answers for all the groups, keeping in mind that if any person in the group answers “yes” to a given question, the group is considered to have answered “yes” to that question.

Consider a group of three people. If:

  • the first person in the group answered “yes” to questions a, b, and c,
  • the second person in the group answered “yes” to questions d, e, and f,
  • and the third person in the group answered “yes” to questions g, h, and i…

…the the group is considered to have answered yes to questions a though i.

To put it mathematically, a group’s answers was the union of the answers of everyone in the group.

With that in mind, I wrote this function:

This function takes advantage of the fact that while Python’s union() is a set method, it can take one or more non-set arguments, as long as it can convert the arguments into a set.

For example, this code:

results in this set:

I rearranged the set so that its items would appear in alphabetical order so that it would be easier to read. This is fine, because with sets, there is no order.

Now that I had count_union_group_answers(), I could apply it to groups

…and get the answer for part one: 6504.

The Day 6 challenge, part two

The challenge

Here’s the text of part two:

As you finish the last group’s customs declaration, you notice that you misread one word in the instructions:

You don’t need to identify the questions to which anyone answered “yes”; you need to identify the questions to which everyone answered “yes”!

Using the same example as above:

This list represents answers from five groups:

  • In the first group, everyone (all 1 person) answered “yes” to 3 questions: ab, and c.
  • In the second group, there is no question to which everyone answered “yes”.
  • In the third group, everyone answered yes to only 1 question, a. Since some people did not answer “yes” to b or c, they don’t count.
  • In the fourth group, everyone answered yes to only 1 question, a.
  • In the fifth group, everyone (all 1 person) answered “yes” to 1 question, b.

In this example, the sum of these counts is 3 + 0 + 1 + 1 + 1 = 6.

For each group, count the number of questions to which everyone answered “yes”. What is the sum of those counts?

Strategy

This time, the goal was to get the total of all the “yes” answers for all the groups, keeping in mind that the group is only considered to have answered “yes” to a given question if every person in the group answered “yes” to that question.

Consider a group of three people. If:

  • the first person in the group answered “yes” to questions a, b, and c,
  • the second person in the group answered “yes” to questions a, e, and f,
  • and the third person in the group answered “yes” to questions a, h, and i…

…the the group is considered to have answered yes to question a, and nothing else.

To put it mathematically, a group’s answers was the intersection of the answers of everyone in the group.

All I had to do was tweak the count_union_group_answers() function from part one to find the intersection of group members’ answers…

…and then apply count_intersection_group_answers() to groups

This gave me the answer for part two: 3351.

Recommended reading

Solutions for other days in Advent of Code 2020