Forum Programmation.autre Advent of Code 2023 : Day 4

Posté par (site web personnel) . Licence CC By‐SA.
3
4
déc.
2023

Jour 4 (résumé)

Partie 1

Le télécabine vous dépose sur une masse de terre flottant dans le ciel, l'île de l'île. Le liftier pense qu'il y a sûrement des sources sur cette île. En revanche, cela dépasse ses compétences, il faudrait aller voir le jardinier, qui habite sur une île entourée d'eau, elle-même sur l'île céleste où nous nous trouvons.

Bref, notre lutin veut bien vous prêter son bateau en échange d'un peu d'aide avec ses cartes à gratter.

Un lutin joueur

Chaque carte a une liste de nombre gagnants et une liste de nombre obtenus, par exemple :

Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11

C'est plutôt simple, pour chaque carte on cherche les numéros gagnants qu'on possède :
* le premier vaut un point,
* les suivants doublent les points obtenus.

On fait la somme des valeurs des cartes et voilà.

La première carte a par exemple 4 numéros gagnants : 83, 86, 17 et 48, ce qui vaut 8 points.
La seconde carte a deux numéros gagnants et vaut 2 points. Et l'ensemble des cartes vaut au final 13 points.

Partie 2

Ces histoires de points, c'est n'importe quoi. On n'invente pas les règles à sa guise, espèce de sagouin ! Il y a des instructions écrites au dos des cartes : chaque carte vous fait gagner une copie supplémentaire d'autant de cartes qui la suivent qu'elle a de numéros gagnants.

Dans l'exemple, la première carte a 4 numéros gagnants, et crée donc une copie supplémentaire des cinq cartes qui la suivent, soit les 2, 3, 4 et 5. Puis on à la carte numéro 2, ou plutôt les deux cartes 2, puisqu'on en a gagné une copie. Et ainsi de suite, avec la garantie qu'aucune carte ne vous fera déborder de la pile.

Enfin, quand on est arrivé au bout, on compte combien de cartes on a. Avec les données d'exemple, on obtient 30 cartes.

  • # En Python

    Posté par (site web personnel) . Évalué à 4.

    #! /usr/bin/python3
    # Advent of Code 2023, day 4
    from __future__ import annotations
    from collections.abc import Iterable
    from typing import Self
    import re
    class Card:
     def __init__(self, id_: int, win_nums: Iterable[int], got_nums: Iterable[int]):
     self.id = id_
     self.win_nums = set(win_nums)
     self.got_nums = set(got_nums)
     self._matches: Optional[int] = None
     pattern = re.compile(r'^Card +(\d+): ([ \d]+) \| ([ \d]+)\n?$')
     @classmethod
     def import_line(cls, line: str) -> Self:
     if (m := cls.pattern.match(line)) is not None:
     return cls(int(m[1]), (int(word) for word in m[2].split()), (int(word) for word in m[3].split()))
     print(line)
     raise ValueError("invalid card description")
     @property
     def matches(self) -> int:
     if self._matches is None:
     self._matches = len(self.win_nums & self.got_nums)
     assert self._matches is not None
     return self._matches
     @staticmethod
     def _num_to_points(num: int) -> int:
     if num <= 0:
     return 0
     return 2 ** (num - 1)
     def points(self) -> int:
     return self._num_to_points(self.matches)
    def solve_both_parts(lines: aoc.Data) -> tuple[int, int]:
     """Solve puzzle parts 1 and 2: determine the sum of all card values and the total number of cards"""
     # Import
     cards: list[int, Card] = []
     for line in lines:
     card = Card.import_line(line)
     cards.append(card)
     # Part 1
     points = sum(card.points() for card in cards)
     # Part 2
     copies = [1 for card in cards]
     for i, card in enumerate(cards):
     for j in range(i + 1, i + 1 + card.matches):
     copies[j] += copies[i]
     return points, sum(copies)
    • [^] # Re: En Python

      Posté par (Mastodon) . Évalué à 2.

      J'aime bien, c'est assez propre et concis !

      Je suis sur quelque chose de nettement moins abstrait, mais l'exercice du jour est assez simple je trouve.

      import sys
      def read_element(winning, numbers):
       winning = set(int(x) for x in winning.strip().split(" ") if x)
       numbers = set(int(x) for x in numbers.strip().split(" ") if x)
       return winning, numbers
      def input():
       for line in sys.stdin:
       game, elements = line.strip().split(':')
       game = int(game.split(" ")[-1].strip())
       winning, numbers = read_element(*elements.strip().split("|"))
       i = numbers.intersection(winning)
       num = len(i)
       score = 2**(num - 1) if i else 0
       yield game, num, score
      datas = [x for x in input()]
      r = sum(s for *_, s in datas)
      print(f"Score : {r}")
      winnings = {card: 1 for card, *_ in datas}
      for card, num, s in datas:
       wins = winnings[card]
       for i in range(card + 1, card + num + 1):
       winnings[i] += wins
      print(f"Total cards: {sum(winnings.values())}")

      Et le calcul est immédiat aussi.

      • Yth.
  • # Simple et rapide

    Posté par . Évalué à 1.

    Une solution simple mais efficace :

    #!/bin/python3
    def game_number(game):
     return int(game.split(":")[0][5:])
    def find_winning(game):
     game = game.split(":")[1].split("|")[0].split(" ")
     w = []
     for n in game:
     if n != "":
     w.append(int(n))
     return w
    def nb_winning(game, winning):
     game = game.split(":")[1].split("|")[1].split(" ")
     nb = 0
     for n in game:
     if n != "":
     if int(n) in winning:
     nb += 1
     return nb
    def solve1(puzzle,testing=False):
     s=0
     for game in puzzle:
     if game == "":
     continue
     nb = nb_winning(game, find_winning(game))
     if nb == 0:
     continue
     points = 1 * (2 ** (nb-1))
     if testing:
     print(game,"had", points, "points beacause of", nb, "winning numbers.")
     s += points
     if testing:
     print(s)
     return s
    def solve2(puzzle,testing=False):
     s = 0
     for i in range(puzzle.count("")):
     puzzle.remove("")
     wons = [1 for i in range(len(puzzle))]
     for game in puzzle:
     num = game_number(game)
     nb = nb_winning(game, find_winning(game))
     if testing:
     print("You had", wons[num-1], "cards", num, "who give you", nb, "cards.")
     for i in range(nb):
     wons[num+i] += wons[num-1]
     s = sum(wons)
     if testing:
     print(s)
     return s
    test1 = """Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
    Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
    Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
    Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
    Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
    Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
    """
    result1 = 13
    test2 = test1
    result2 = 30
    def solve(short=False):
     print("----Part 1----")
     if short == False:
     if solve1(test1.split("\n"),testing=True) != result1:
     print("Not working.")
     return False
     else :
     print("Maybe working?")
     with open("input.txt",'r') as file:
     lines = file.read().split("\n")
     s1 = solve1(lines)
     print(s1)
     print("----Part 2----")
     if short == False:
     if solve2(test2.split("\n"),testing=True) != result2:
     print("Not working.")
     return False
     else :
     print("Maybe working?")
     with open("input.txt",'r') as file:
     lines = file.read().split("\n")
     s2 = solve2(lines)
     print(s2)
     return s1, s2
    if __name__ == "__main__":
     from sys import argv
     try:
     if argv[1] == "--summary" or argv[1] == "-s":
     solve(short=True)
     except IndexError:
     solve()

    J'ai trouvé le problème étonnamment simple, j'y suis arrivé du premier coup pour les deux parties.

    Et contrairement à beaucoup de monde ce jour-là, cette solution est presque instantanée à l'exécution, de l'ordre de 0.01 sec.

    L'informatique n'est pas une science exacte, on n'est jamais à l'abri d'un succès

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.