День 2: Камень, ножницы, бумага.
Первая часть.
Полную прозу головоломки читайте здесь: https://adventofcode.com/2022/day/2
TL;DR ввода образца головоломки.
- Наш пример головоломки представляет собой игру для двух игроков «камень-ножницы-бумага».
- Левая колонка содержит ходы, сделанные противником, а правая — ходы, сделанные нами. Таким образом, каждая строка в образце ввода представляет один раунд игры.
- Игра в камень, ножницы или бумагу приносит игроку 1, 2 и 3 очка соответственно.
- A, B и C соответственно представляют камень, ножницы и бумагу в исполнении противника.
X, Y и Z соответственно представляют камень, ножницы и бумагув нашем исполнении. - Кроме того:
- Если мы выигрываем раунд (обыгрываем противника), мы получаем 6 дополнительных очков сверх очков, полученных за камень, ножницы или бумагу.
- Если мы проигрываем раунд, мы получаем 0 дополнительных очков.
- Если мы сыграем вничью, мы получим 3 дополнительных очка.
A Y B X C Z
В первом раунде приведенного выше примера головоломки противник играл в камень (1 балл), а мы играли в бумагу (2 балла). Мы также выиграли этот раунд — бумага побеждает камень — и, следовательно, получили 6 дополнительных очков за эту победу.
В этом раунде мы набрали в общей сложности 2 + 6 = 8
очков.
Задание.
Наша задача — найти общее количество очков, которое мы получили бы после завершения всех раундов, если бы игра шла точно так, как диктует ввод головоломки.
Мыслительный процесс с кодом.
- Сохраните этот ввод головоломки как некоторую структуру данных.
Как и в первый день, мы будем хранить входные данные образца головоломки в виде списка Python.
sample_input = """ A Y B X C Z """.strip().splitlines()
sample_input
теперь представляет этот список:
['A Y', 'B X', 'C Z']
- Храните информацию о камне, ножницах и бумаге — что лучше чего и сколько очков стоит каждый.
Из многих путей, которые мы можем использовать для хранения информации о камне, ножницах, бумаге, сегодня мы будем использовать словарь Python.
Словарь — который я в дальнейшем буду называть dict — позволяет нам ассоциировать что-то с чем-то другим, где «что-то» — это ключ, а «что-то еще» — это значение для этого ключа.
Позже мы можем найти ключ, чтобы получить значение.
Мы могли бы создать один словарь для информации оппонентов, а другой — для себя, но это усложняет будущие поиски, поскольку для получения полезных выводов необходимо исследовать оба словаря.
Кроме того, эти два отдельных словаря неизбежно будут содержать повторяющуюся информацию. .
Вместо этого мы создадим один словарь с именем stats
, в котором будет храниться вся необходимая информация о камнях, бумаге и ножницах.
Мы создадим словарь с нашей точки зрения, так что ключи X, Y, Z — это камень, ножницы и бумага, а значения — необходимая информация для каждого из этих трех ключей.
# rock, paper, scissors information from our perspective stats = { 'X': {'score': 1, 'beats': 'C', 'beaten by': 'B', 'draws with': 'A'}, 'Y': {'score': 2, 'beats': 'A', 'beaten by': 'C', 'draws with': 'B'}, 'Z': {'score': 3, 'beats': 'B', 'beaten by': 'A', 'draws with': 'C'}, }
Словарь stats
в достаточной степени хранит необходимую информацию для каждого из наших возможных вариантов, а также для того, как эти варианты соотносятся с вариантами оппонента.
Элемент словаря:
'X': {'score': 1, 'beats': 'C', 'beaten by': 'B', 'draws with': 'A'},
Имеет ключ, X, который является нашей версией rock.
Значением для X являются все детали, сохраненные как еще один диктат, включая счет за камень и то, как наш камень связан с собственными вариантами противника.
- Сохраняйте информацию о том, сколько стоят выигрыш, ничья и проигрыш.
В нашем словаре stats
по-прежнему отсутствует информация о том, что такое выигрыш, ничья и проигрыш с точки зрения их числового значения.
Для этого мы можем создать три константы для хранения этой информации.
WIN = 6 DRAW = 3 LOSS = 0
- Посетите каждый раунд игры, стараясь извлечь ход противника, а также наш.
- Найдите и запишите счет нашего хода в
stats
словаре. - Все еще используя наш
stats
dict, проверьте, побеждает ли наш ход, выигрывает ли он или делает ничью с ходом нашего противника, принимая к сведению результат игры для каждого раунда.
our_total_score = 0 for game_round in sample_input: # extract both moves opponent_move, our_move = game_round.strip().split() # note our move's score our_move_score = stats[our_move]['score'] outcome_score = 0 # update the outcome based on if we played a # winning, drawing, or losing move if stats[our_move]['beats'] == opponent_move: outcome_score += WIN elif stats[our_move]['beaten by'] == opponent_move: outcome_score += LOSS else: outcome_score += DRAW our_total_score += (our_move_score + outcome_score)
- our_total_score в конце всех раундов — это решение головоломки.
print(our_total_score)
В целом наш код выглядит так:
# rock, paper, scissors information from our perspective stats = { 'X': {'score': 1, 'beats': 'C', 'beaten by': 'B', 'draws with': 'A'}, 'Y': {'score': 2, 'beats': 'A', 'beaten by': 'C', 'draws with': 'B'}, 'Z': {'score': 3, 'beats': 'B', 'beaten by': 'A', 'draws with': 'C'}, } WIN = 6 DRAW = 3 LOSS = 0 our_total_score = 0 for game_round in sample_input: # extract the opponent's move, and ours opponent_move, our_move = game_round.strip().split() # note our move's score our_move_score = stats[our_move]['score'] outcome_score = 0 # update the outcome based on if we played a # winning, drawing, or losing move if stats[our_move]['beats'] == opponent_move: outcome_score += WIN elif stats[our_move]['beaten by'] == opponent_move: outcome_score += LOSS else: outcome_score += DRAW our_total_score += (our_move_score + outcome_score) print(our_total_score)
Часть вторая.
Вспоминая тот же ввод головоломки:
A Y B X C Z
Новая структура.
Левая колонка — это по-прежнему ходы, сделанные противником. A, B и C по-прежнему камень, ножницы, бумага.
Однако правая колонка больше не представляет наши ходы.
Теперь она представляет результат игры.
X — проигрыш, Y — ничья, Z — выигрыш с нашей точки зрения. просмотр.
Победа, ничья и поражение по-прежнему приносят 6, 3 и 0 очков соответственно.
В первой строке написано, что противник играл в рок (A), а мы с ним сыграли вничью (Y).
Значит, мы тоже должны были сыграть в рок!
Новая задача.
Найдите наш общий счет за все раунды, если мы выиграли, проиграли или сыграли вничью, в соответствии с требованиями выборки.
- Мы по-прежнему будем хранить этот ввод, как и раньше, с
sample_input
, представляющим этот список:
['A Y', 'B X', 'C Z']
Мыслительный процесс с кодом.
- Посетите каждый раунд игры, обязательно извлекая ход противника, а также результат этого раунда.
- Добавьте балл за этот результат к нашему общему баллу.
- Решите, основываясь на результате, какой ход мы должны были сделать, чтобы достичь этого результата.
- Получите оценку нашего хода и добавьте ее к общему счету.
Чтобы достичь этого, нам нужно знать, что каждый ход противника выигрывает, с чем сводит вничью и проигрывает.
Создание словаря для противника — хорошее место для начала.
Диктовка является отражением приведенной ниже таблицы, где R
, P
и S
— наши ходы; камень, ножницы и бумага соответственно.
+----------+-------+--------+-------+ | Opponent | Beats | beaten | draws | | move | | by | with | +----------+-------+--------+-------+ | A | S | P | R | +----------+-------+--------+-------+ | B | R | S | P | +----------+-------+--------+-------+ | C | P | R | S | +----------+-------+--------+-------+
Диктант выглядит следующим образом:
opponent_moves = { 'A': {'score': 1, 'beats': 'S', 'beaten by': 'P', 'draws with': 'R'}, 'B': {'score': 2, 'beats': 'R', 'beaten by': 'S', 'draws with': 'P'}, 'C': {'score': 3, 'beats': 'P', 'beaten by': 'R', 'draws with': 'S'}, }
Нам все еще нужно сохранить некоторую информацию о ходах R
, P
и S
, которые мы только что составили.
Как насчет еще одного словаря?
our_moves = { 'R': {'score': 1}, 'P': {'score': 2}, 'S': {'score': 3} }
Итак, мы знаем информацию о ходах противника, да и о наших ходах.
Наша программа еще не знает, что такое проигрыш, ничья и выигрыш. Давай-ка скажем — ты предвидел это — с другим словарем!
outcomes = { 'X': {'name': 'loss', 'score': 0}, 'Y': {'name': 'draw', 'score': 3}, 'Z': {'name': 'win', 'score': 6}, }
Хотя на данный момент ключ name
кажется излишним, он немного облегчит читаемость нашего кода, когда мы соберем его воедино.
Нам не нужно забывать инициализировать наш общий счет, который при печати в конце программы будет решением головоломки.
our_total_score = 0
В целом наш код выглядит так:
sample_input = """ A Y B X C Z """.strip().splitlines() opponent_moves = { 'A': {'score': 1, 'beats': 'S', 'beaten by': 'P', 'draws with': 'R'}, 'B': {'score': 2, 'beats': 'R', 'beaten by': 'S', 'draws with': 'P'}, 'C': {'score': 3, 'beats': 'P', 'beaten by': 'R', 'draws with': 'S'}, } our_moves = { 'R': {'score': 1}, 'P': {'score': 2}, 'S': {'score': 3} } outcomes = { 'X': {'name': 'loss', 'score': 0}, 'Y': {'name': 'draw', 'score': 3}, 'Z': {'name': 'win', 'score': 6}, } our_total_score = 0
Теперь, упорядочив всю необходимую информацию, мы можем посетить каждый раунд в образце ввода.
for game_round in sample_input: # extract the opponent's move, and outcome of the round opponent_move, outcome = game_round.strip().split() # determine what our move was, based on the opponent's own move, # and the outcome of the game if outcomes[outcome]['name'] == 'win': our_move = opponent_moves[opponent_move]['beaten by'] elif outcomes[outcome]['name'] == 'loss': our_move = opponent_moves[opponent_move]['beats'] else: our_move = opponent_moves[opponent_move]['draws with'] # our score is the score for our move and that of the outcome our_total_score += our_moves[our_move]['score'] our_total_score +=outcomes[outcome]['score']
После посещения всех раундов our_total_score
теперь будет содержать ответ, который мы ищем. Печать общего балла покажет указанный ответ
print(our_total_score)
И это все, что нам нужно.
Все вместе выглядит так:
sample_input = """ A Y B X C Z """.strip().splitlines() opponent_moves = { 'A': {'score': 1, 'beats': 'S', 'beaten by': 'P', 'draws with': 'R'}, 'B': {'score': 2, 'beats': 'R', 'beaten by': 'S', 'draws with': 'P'}, 'C': {'score': 3, 'beats': 'P', 'beaten by': 'R', 'draws with': 'S'}, } our_moves = { 'R': {'score': 1}, 'P': {'score': 2}, 'S': {'score': 3} } outcomes = { 'X': {'name': 'loss', 'score': 0}, 'Y': {'name': 'draw', 'score': 3}, 'Z': {'name': 'win', 'score': 6}, } our_total_score = 0 for game_round in sample_input: # extract the opponent's move, and outcome of the round opponent_move, outcome = game_round.strip().split() # determine what our move was, based on the opponent's own move, # and the outcome of the game if outcomes[outcome]['name'] == 'win': our_move = opponent_moves[opponent_move]['beaten by'] elif outcomes[outcome]['name'] == 'loss': our_move = opponent_moves[opponent_move]['beats'] else: our_move = opponent_moves[opponent_move]['draws with'] # our score is the score for our move and that of the outcome our_total_score += our_moves[our_move]['score'] our_total_score +=outcomes[outcome]['score']
И это итоги второго дня! 🎉🎉🎉
Не спускайте глаз с третьего дня. 👋