• # Pourquoi des dictionnaires ?

    Posté par (site web personnel) . En réponse au message Advent of Code, jour 15. Évalué à 2. Dernière modification le 15 décembre 2023 à 13:10.

    Pourquoi utilisez-vous des dictionnaires plutôt qu'un tableau ? On a 256 boîtes, indexées par un entier de 0 à 255, ça semble naturel de représenter ça par un tableau de 256 boîtes non ?

    Mon code :

    from enum import Enum
    from dataclasses import dataclass
    import io
    import re
    from typing import Optional, Self
    import aoc
    def hash_(s: bytes) -> int:
     value = 0
     for b in s:
     value += b
     value *= 17
     value %= 256
     return value
    @dataclass(frozen=True)
    class Lens:
     focal: int
     label: bytes
     def __str__(self) -> str:
     return '%s%d' % (self.label.decode(), self.focal)
    class Operation(Enum):
     REM = '-'
     PUT = '='
    class Instruction:
     def __init__(self, label: bytes, op: Operation, arg: Optional[int] = None):
     self.label = label
     self.box = hash_(label)
     self.op = op
     self.arg = arg
     pattern = re.compile('^(.+)([=-])(.*)$')
     @classmethod
     def import_word(cls, word: str) -> Self:
     if (m := cls.pattern.match(word)) is not None:
     label = m[1].encode('ascii')
     op = Operation(m[2])
     arg = None
     if (s := m[3]) != '':
     arg = int(s)
     return cls(label, op, arg)
     raise ValueError('cannot parse instruction')
    class Box:
     def __init__(self) -> None:
     self.lenses: list[Lens] = []
     def remove(self, label: bytes) -> None:
     for i, lens in enumerate(self.lenses):
     if lens.label == label:
     del self.lenses[i]
     return
     def put(self, new_lens: Lens):
     for i, lens in enumerate(self.lenses):
     if lens.label == new_lens.label:
     self.lenses[i] = new_lens
     return
     self.lenses.append(new_lens)
     def is_empty(self) -> bool:
     return len(self.lenses) == 0
     def __str__(self) -> str:
     return ' '.join("[%s]" % str(lens) for lens in self.lenses)
    class Machine:
     def __init__(self) -> None:
     self.boxes: tuple[Box] = tuple(Box() for _ in range(256)) # type: ignore
     def __str__(self) -> str:
     s = io.StringIO()
     for i, box in enumerate(self.boxes):
     if not box.is_empty():
     s.write('Box %d: %s\n' % (i, str(box)))
     return s.getvalue()
     def apply(self, instruction: Instruction) -> None:
     box = self.boxes[instruction.box]
     if instruction.op is Operation.REM:
     box.remove(instruction.label)
     return
     if instruction.op is Operation.PUT and instruction.arg is not None:
     lens = Lens(instruction.arg, instruction.label)
     box.put(lens)
     return
     raise ValueError("invalid instruction")
     def power(self) -> int:
     total = 0
     for box_number, box in enumerate(self.boxes):
     for lens_number, lens in enumerate(box.lenses):
     total += (box_number + 1) * (lens_number + 1) * lens.focal
     return total
    def part1(lines: aoc.Data) -> int:
     """Solve puzzle part 1: determine the sum of hash value of all instructions"""
     total = 0
     for line in lines:
     for part in line.rstrip().split(','):
     h = hash_(part.encode('ascii'))
     total += hash_(part.encode('ascii'))
     return total
    def part2(lines: aoc.Data) -> int:
     """Solve puzzle part 2: determine the sum of staff"""
     instructions = (Instruction.import_word(part) for line in lines for part in line.rstrip().split(','))
     machine = Machine()
     for instruction in instructions:
     machine.apply(instruction)
     return machine.power()