create account

Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018 by steempytutorials

View this thread on: hive.blogpeakd.comecency.com
· @steempytutorials ·
$21.19
Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018
![banner.png](https://www.digifloor.com/wp-content/uploads/2016/07/python-banner.jpg)

---

#### Repository
https://github.com/python

#### What will I learn

- What are defaultdicts?
- Extracting arguments with re.search
- Retrieving the max value of a dict

#### Requirements

- Python 3.7.2
- [Pipenv](https://pypi.org/project/pipenv/)
- git

#### Difficulty

- basic

---

### Tutorial

#### Preface

This tutorial is part of a course where solutions to puzzles from [Advent of Code 2018](https://adventofcode.com/2018/) are discussed to explain programming techniques using Python. Each puzzle contains two parts and comes with user specific inputs. It is recommended to try out the puzzle first before going over the tutorial. Puzzles are a great and fun way to learn about programming.

While the puzzles start of relatively easy and get more difficult over time. Basic programming understanding is required. Such as the different type of variables, lists, dicts, functions and loops etc. A course like [Learn Python2 from Codeacademy](https://www.codecademy.com/learn/learn-python) should be sufficient. Even though the course is for Python two, while Python 3 is used.

This tutorial will look at [puzzle 4](https://adventofcode.com/2018/day/4)

The code for this tutorial can be found on [Github](https://github.com/Juless89/tutorials-aoc)!

#### Puzzle 4

This puzzle is about guards that are performing a shift and fall asleep during that shift. Somebody has spied on the guards and for each guard, the guard id, the moment the guard falls asleep and when the guard wakes up again are recorded. The idea is to analyse this information to think of a plan to circumvent the guard.

#### Part one

> Strategy 1: Find the guard that has the most minutes asleep. What minute does that guard spend asleep the most? What is the ID of the guard you chose multiplied by the minute you chose?

Taken from the puzzle question the total amount of `minutes` and the `frequency` per minute are needed to answer this question. To store this data `defaultdicts` will be used.

#### What are defaultdicts?

Unlike normal dicts when creating a new `key`, `value` pair or asking for a `key` that does not exist. Insteed of an error a default `value` will be returned or set. In the case one wants to increment a `value` inside the dict. If the key does not exist it will be added to the default `value`. 

```
from collections import defaultdict


# totals holds the total amount of minutes a guard has spent sleeping
# frequency holds the frequency per minute (0-59) for each guard 
totals = defaultdict(int)
frequency = defaultdict(lambda: defaultdict(int))
```
<br>
In python `lamba` is used to pass a function. In this case it creates a new `defaultdict` when the default value is called. Thereby creating a nested dict structure. However, the nested dict is not created until the the first time a new key is called.

<center>![Apr-11-2019 20-20-06.gif](https://cdn.steemitimages.com/DQme1pN49EAJNXB7LrXqvJTGoZikrjQmqr94R6JHtKabWWH/Apr-11-2019%2020-20-06.gif)</center>

#### Extracting arguments with re.search

The input for this puzzle has again become more complicated than seen so far. It is important to note that there is always only 1 guard on duty. The minute the guard falls asleep is included and the minute the guard wakes up is not. All guards only sleep between `0:00` and `0:59`.

```
[1518-11-01 00:00] Guard #10 begins shift
[1518-11-01 00:05] falls asleep
[1518-11-01 00:25] wakes up
```

Each line contains a `timestamp` and an action. There are three different actions. When a guard starts a shift, the guard ID has to be extraced. If `asleep` or `wakes` is inside the line the start and end minute can be extracted. 

```
# sort lines by timestamp
for line in sorted(lines):
    # parse minute
    minute = int(re.search(r':(\d+)', line).group(1))
    if '#' in line:
        guard = int(re.search(r'#(\d+)', line).group(1))
    # guards falls asleep, minute included
    elif 'asleep' in line:
        start = minute
    # guard wakes up, minute not included
    elif 'wakes' in line:
        end = minute 

        # for each minute add to totals and frequency
        for m in range(start, end):
            totals[guard] += 1
            frequency[guard][m] += 1
```

The input does not come `sorted`. Python is clever enough to recognize the timestamp at the start of each line. To sort the input only `sorted()` had to be applied to the list of lines. Extracting the `minute` and `guard` id is done by using `re.search()`. Which requires a pattern and a string. `r':(\d+)` takes all digits after the `:` and `r'#(\d+)'` does the same but after a `#`. This functions returns a match object, to retrieve the value `group(1)` has to be called on the object.

When the input is `sorted`, whenever a guard wakes up all data for this shift is done and the guard can be added to the dicts. This is done for the range `start`, `end`. Which included the start minute but excludes the end minute.

#### Retrieving the max value of a dict

To solve the first puzzle the guard that has the most minutes of sleep has to be found and the minute this guard has been asleep the most. Since the data is inside dicts using a `max()` function is not as straight forward.

`.items()` returns the a list of tuples `(key, value)`. 
```
dict_items([(661, 498), (1663, 512), (419, 439), (859, 408), (2383, 216), (997, 466), (1367,
348), (61, 148), (3407, 385), (3391, 419), (739, 450), (2221, 253), (2297, 391), (2113, 198),
(1163, 323), (3203, 337), (733, 570), (113, 151), (2609, 222), (2713, 194)])
```

To retrieve the max value for the value an `itemgetter` can be used and passed as the key to the `max()` function.

```
from operator import itemgetter

def part_1(totals, frequency):
    key = itemgetter(1) 
    guard = max(totals.items(), key=key)[0]
    minute = max(frequency[guard].items(), key=key)[0]
    return guard * minute
```

`itemgetter(1)` sets the index to 1, that of the value. Since the actual max value is not required, it just needs to be sorted by this value. `[0]` retrieves the first element. 

> What is the ID of the guard you chose multiplied by the minute you chose?

The answer can then be calculated with: `guard * minute`

#### Part two

> Strategy 2: Of all guards, which guard is most frequently asleep on the same minute? What is the ID of the guard you chose multiplied by the minute you chose?

Solving this puzzle can be done by looping through all the `guards` inside the `frequency` dict. For each `guard` retrieve the `minute` with the heigest `frequency` and store that with the `score` (guard ID * minute). At the end sort the list and retrieve score associated with the highest `frequency`.

```
def part_2(frequency):
    items = []
    key = itemgetter(1) 

    # for each guard retrieve the minute with the highest
    # frequency. Store freq and score (guard * minute)
    for guard in frequency:
        minute, freq = max(frequency[guard].items(), key=key)
        items.append((freq, guard * minute))

    # return by highest frequency 
    return sorted(items)[-1][1]
```

By default `sorted()` will look at the first value inside the set to sort the list of sets. And sorts from low to high.
```
before
[(14, 21813), (14, 51553), (13, 14246), (12, 36937), (7, 69107), (19, 37886), (12, 58781), (7, 2196), (12, 126059), (13, 125467), (16, 35472), (8, 71072), (13, 84989), (5, 71842), (9, 38379), (10, 99293), (17, 35184), (5, 3164), (8, 62616), (7, 116659)]

after sorted()
[(5, 3164), (5, 71842), (7, 2196), (7, 69107), (7, 116659), (8, 62616), (8, 71072), (9, 38379), (10, 99293), (12, 36937), (12, 58781), (12, 126059), (13, 14246), (13, 84989), (13, 125467), (14, 21813), (14, 51553), (16, 35472), (17, 35184), (19, 37886)]
```

The wanted value is at the end of the list, index `[-1]` and is the 2nd item in the set, index `[1]`.


#### Running the code

Run the code with: `python main.py`

```
if __name__ == "__main__":
    # parse input into totals and frequency dicts
    totals, frequency = parse_input()

    print(f'Part 1 Answer: {part_1(totals, frequency)}')
    print(f'Part 2 Answer: {part_2(frequency)}')
```
<br>
<center>![Screenshot 2019-04-11 at 21.31.21.png](https://cdn.steemitimages.com/DQme8hsQJ6oUFrCxX8oiVsfCJ3W8tXqamtvk4rASL92RM1q/Screenshot%202019-04-11%20at%2021.31.21.png)</center>

#### Curriculum
[Part 1](https://steemit.com/utopian-io/@steempytutorials/learn-how-to-program-with-python-1---solving-puzzles-from-advent-of-code-2018), [Part 2](https://steemit.com/utopian-io/@steempytutorials/learn-how-to-program-with-python-2---solving-puzzles-from-advent-of-code-2018), [Part 3](https://steemit.com/utopian-io/@steempytutorials/learn-how-to-program-with-python-3---solving-puzzles-from-advent-of-code-2018)

---

The code for this tutorial can be found on [Github](https://github.com/Juless89/tutorials-aoc)!

This tutorial was written by @juliank.
πŸ‘  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 85 others
properties (23)
authorsteempytutorials
permlinklearn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018
categoryutopian-io
json_metadata{"tags":["utopian-io","tutorials","python","programming","course"],"app":"steem-plus-app"}
created2019-04-11 19:36:00
last_update2019-04-11 19:36:00
depth0
children5
last_payout2019-04-18 19:36:00
cashout_time1969-12-31 23:59:59
total_payout_value15.898 HBD
curator_payout_value5.288 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length8,940
author_reputation31,094,047,689,691
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries
0.
accountsteemplus-pay
weight100
1.
accountutopian.pay
weight500
max_accepted_payout100,000.000 HBD
percent_hbd10,000
post_id82,903,133
net_rshares36,879,301,417,685
author_curate_reward""
vote details (149)
@portugalcoin ·
$5.90
Thank you for your contribution @steempytutorials.
After reviewing your tutorial we suggest the following points listed below:

- Your tutorial is very interesting in helping to solve a puzzle with code.

- Your tutorial is very well structured and explained. It's very nice to be careful to write the text for readers who may not be very experienced in python language.

- We suggest that you put the title a little less extensive, but that contains the key words of what you will explain in your tutorial.

Good work on developing this tutorial, we look forward to your next contribution.

Your contribution has been evaluated according to [Utopian policies and guidelines](https://join.utopian.io/guidelines), as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, [click here](https://review.utopian.io/result/8/3-2-1-1-1-2-2-3-).

---- 
Need help? Chat with us on [Discord](https://discord.gg/uTyJkNm).

[[utopian-moderator]](https://join.utopian.io/)
πŸ‘  , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authorportugalcoin
permlinkre-steempytutorials-learn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018-20190412t181710979z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"users":["steempytutorials"],"links":["https://join.utopian.io/guidelines","https://review.utopian.io/result/8/3-2-1-1-1-2-2-3-","https://discord.gg/uTyJkNm","https://join.utopian.io/"],"app":"steemit/0.1"}
created2019-04-12 18:17:12
last_update2019-04-12 18:17:12
depth1
children1
last_payout2019-04-19 18:17:12
cashout_time1969-12-31 23:59:59
total_payout_value4.524 HBD
curator_payout_value1.376 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,042
author_reputation599,460,335,323,040
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id82,973,788
net_rshares9,790,807,752,840
author_curate_reward""
vote details (24)
@utopian-io ·
Thank you for your review, @portugalcoin! Keep up the good work!
properties (22)
authorutopian-io
permlinkre-re-steempytutorials-learn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018-20190412t181710979z-20190414t200319z
categoryutopian-io
json_metadata"{"app": "beem/0.20.17"}"
created2019-04-14 20:03:21
last_update2019-04-14 20:03:21
depth2
children0
last_payout2019-04-21 20:03:21
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length64
author_reputation152,955,367,999,756
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id83,097,072
net_rshares0
@steem-ua ·
#### Hi @steempytutorials!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
**Feel free to join our [@steem-ua Discord server](https://discord.gg/KpBNYGz)**
properties (22)
authorsteem-ua
permlinkre-learn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018-20190412t183417z
categoryutopian-io
json_metadata"{"app": "beem/0.20.19"}"
created2019-04-12 18:34:18
last_update2019-04-12 18:34:18
depth1
children0
last_payout2019-04-19 18:34:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length295
author_reputation23,214,230,978,060
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id82,974,560
net_rshares0
@trufflepig ·
**Congratulations!** Your post has been selected as a daily Steemit truffle! It is listed on **rank 23** of all contributions awarded today. You can find the [TOP DAILY TRUFFLE PICKS HERE.](https://steemit.com/@trufflepig/daily-truffle-picks-2019-04-12) 
    
I upvoted your contribution because to my mind your post is at least **10 SBD** worth and should receive **249 votes**. It's now up to the lovely Steemit community to make this come true.

I am `TrufflePig`, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, [you can find an explanation here!](https://steemit.com/steemit/@trufflepig/weekly-truffle-updates-2019-14)
    
Have a nice day and sincerely yours,
![trufflepig](https://raw.githubusercontent.com/SmokinCaterpillar/TrufflePig/master/img/trufflepig17_small.png)
*`TrufflePig`*
    
properties (22)
authortrufflepig
permlinkre-learn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018-20190412t160532
categoryutopian-io
json_metadata""
created2019-04-12 16:05:33
last_update2019-04-12 16:05:33
depth1
children0
last_payout2019-04-19 16:05:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length885
author_reputation21,266,577,867,113
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id82,965,976
net_rshares0
@utopian-io ·
Hey, @steempytutorials!

**Thanks for contributing on Utopian**.
We’re already looking forward to your next contribution!

**Get higher incentives and support Utopian.io!**
 Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via [SteemPlus](https://chrome.google.com/webstore/detail/steemplus/mjbkjgcplmaneajhcbegoffkedeankaj?hl=en) or [Steeditor](https://steeditor.app)).

**Want to chat? Join us on Discord https://discord.gg/h52nFrV.**

<a href='https://steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1'>Vote for Utopian Witness!</a>
properties (22)
authorutopian-io
permlinkre-learn-how-to-program-with-python-4---solving-puzzles-from-advent-of-code-2018-20190412t214018z
categoryutopian-io
json_metadata"{"app": "beem/0.20.17"}"
created2019-04-12 21:40:21
last_update2019-04-12 21:40:21
depth1
children0
last_payout2019-04-19 21:40:21
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length598
author_reputation152,955,367,999,756
root_title"Learn how to program with Python #4 - Solving Puzzles from Advent of Code 2018"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id82,984,443
net_rshares0