- Published on

# Advent of Code 2023: Day 4 Solution

- Authors
- Name
- Tinker Assist

Advent of Code 2023 - Day 4 - Scratchcards

## Table of Contents

# Part 1 Solution

We'll need to begin by reading the puzzle input

### Read the Puzzle Input File

We will save our puzzle input in "day4_input.txt" and then read from that file.

```
file = open("day4_input.txt", "r")
input = file.read()
```

We will then break up the input by line:

```
input_list = input.split('\n')
```

### Create Solution structure

```
points = 0
for card in input_list:
# We will add to our points here
print(points)
```

### Get Winning Numbers and Numbers You Have

To retrieve all of the winning values from our input line, we need to do the following:

- Get all characters to the right of the
`:`

```
card.split(':')[1]
```

- Get all remaining characters to the left of the
`|`

```
card.split(':')[1].split('|')[0]
```

- Seperate values using space characters as the delimeter

```
card.split(':')[1].split('|')[0].split(' ')
```

- Turn each value from the list into an integer

```
[int(i) for i in card.split(':')[1].split('|')[0].split(' ')]
```

- Remove all stray spaces and null values in our list

```
[int(i) for i in card.split(':')[1].split('|')[0].split(' ') if i.isdigit()]
```

We can use the same methodology for the Numbers You Have, but instead read all values after the `|`

by indexing 1 instead of 0.

```
[int(i) for i in card.split(':')[1].split('|')[1].split(' ') if i.isdigit()]
```

It is messy, but it works :)

So now, our code looks as follows

```
points = 0
for card in input_list:
winning_nums = [int(i) for i in card.split(':')[1].split('|')[0].split(' ') if i.isdigit()]
your_nums = [int(i) for i in card.split(':')[1].split('|')[1].split(' ') if i.isdigit()]
print(points)
```

### Compare Your Numbers to Winning Numbers

Now we will loop through each number in the list of Your Numbers and identify those that are in the Winning Numbers. If the number at any given index is in the Winning Numbers, we will increment a variable `winners`

```
winners = 0
for your_num in your_nums:
winners += 1 if your_num in winning_nums else 0
```

### Count the Points:

Now, we need to add to our points variable based on how many winners were found on our card. We can do this as follows

```
points += 2**(winners-1) if winners > 0 else 0
```

And that's it!

### The Code

```
points = 0
for card in input_list:
winning_nums = [int(i) for i in card.split(':')[1].split('|')[0].split(' ') if i.isdigit()]
your_nums = [int(i) for i in card.split(':')[1].split('|')[1].split(' ') if i.isdigit()]
winners = 0
for your_num in your_nums:
winners += 1 if your_num in winning_nums else 0
points += 2**(winners-1) if winners > 0 else 0
print(points)
```

# Part 2 Solution

### Create Solution Structure

We can Recycle much of the code from our part 1 solution. Let's start with the following and build from there

```
for card in input_list:
winning_nums = [int(i) for i in card.split(':')[1].split('|')[0].split(' ') if i.isdigit()]
your_nums = [int(i) for i in card.split(':')[1].split('|')[1].split(' ') if i.isdigit()]
winners = 0
for your_num in your_nums:
winners += 1 if your_num in winning_nums else 0
```

In this part, we will need to reference the index of a given input line. We can update our input read for loop as follows to get the index

```
for ind_card, card in enumerate(input_list):
```

Additionally, let's add a list that we can use to track how many copies of each scratchcard we have at any given time. We can do this above our for loop

```
cards = [1]*len(input_list)
```

### Counting Card copies

After we have collected the number of winners on a given card, we can go through each subsequent card and distribute copies. Remember, we must distribute one copy for every copy of the card we just scratched.

```
for i in range(0,winners):
cards[ind_card+i+1] += cards[ind_card]
```

However, we must be sure not to distribute copies for indexes beyond the length of our input. Thus, we need to modify as follows

```
for i in range(0,winners):
if ind_card+i+1 < len(input_list):
cards[ind_card+i+1] += cards[ind_card]
```

That's it! Now we can print the sum of all of our cards. The full solution is below.

### The Code

```
# part 2
cards = [1]*len(input_list)
for ind_card, card in enumerate(input_list):
winning_nums = [int(i) for i in card.split(':')[1].split('|')[0].split(' ') if i.isdigit()]
your_nums = [int(i) for i in card.split(':')[1].split('|')[1].split(' ') if i.isdigit()]
winners = 0
for your_num in your_nums:
winners += 1 if your_num in winning_nums else 0
for i in range(0,winners):
if ind_card+i+1 < len(input_list):
cards[ind_card+i+1] += cards[ind_card]
print(sum(cards))
```

# Full code

Get the full code here.