• # ready, set, python

    Posté par . En réponse au message Avent du Code, jour 23. Évalué à 4. Dernière modification le 23 décembre 2022 à 18:15.

    Pas si difficile aujourd'hui mais j'ai butté sur à peut prêt toutes les instructions
    - ah si un elf peut bouger partout alors il ne bouge pas ?!
    - ah les directions changent a chaque tour ?!
    - mais qu'est ce qu'il se passe au bord ?
    - ah la grille est infinie ?!

    Ce dernier point m'a contraint à changer ma conception : d'une matrice à un set. Moins sympa pour débuguer mais nécessaire quand on ne connaît pas les limites du jeu. Finalement un code plus simple car pas de gestion de dépassement, et utilisation des fonctions de set (appartenance, union, différences) et des list comprehension un peu partout. Et accessoirement beaucoup plus rapide : 1025 round en 8s pour le tout.

    python, 60 loc

    import sys
    E = set() # elves
    for y,l in enumerate(sys.stdin.read().splitlines()):
     for x,c in enumerate(l):
     if c == '#':
     E.add((y,x))
    def can(y,x):
     can1 = (y-1,x-1) not in E
     can2 = (y-1,x) not in E
     can3 = (y-1,x+1) not in E
     can4 = (y,x+1) not in E
     can5 = (y+1,x+1) not in E
     can6 = (y+1,x) not in E
     can7 = (y+1,x-1) not in E
     can8 = (y,x-1) not in E
     return [can1,can2,can3,can4,can5,can6,can7,can8]
    def canN(y,x,can1,can2,can3,can4,can5,can6,can7,can8):
     if can1 and can2 and can3:
     return (y-1,x)
    def canS(y,x,can1,can2,can3,can4,can5,can6,can7,can8):
     if can5 and can6 and can7:
     return (y+1,x)
    def canW(y,x,can1,can2,can3,can4,can5,can6,can7,can8):
     if can7 and can8 and can1:
     return (y,x-1)
    def canE(y,x,can1,can2,can3,can4,can5,can6,can7,can8):
     if can3 and can4 and can5:
     return (y,x+1)
    from collections import deque
    dirs = deque([canN,canS,canW,canE])
    for r in range(int(sys.argv[1])):
     P = dict()
     for e in E: # each elve
     (y,x) = e
     moves = [ d(y,x,*can(y,x)) for d in dirs ]
     if all(m is not None for m in moves):
     continue
     if all(m is None for m in moves):
     continue
     p = next(filter(lambda m: m is not None, moves))
     if p not in P: # can move
     P[p] = (y,x)
     else: # occupied, invalidate move
     P[p] = None
     moved = { v for k,v in P.items() if v is not None }
     newpos = { k for k,v in P.items() if v is not None }
     if r+1 == 10:
     minx = min(x for (x,_) in E)
     maxx = max(x for (x,_) in E)
     miny = min(y for (_,y) in E)
     maxy = max(y for (_,y) in E)
     print((maxx-minx+1) * (maxy-miny+1) - len(E))
     if len(newpos) == 0:
     print(f"no move after {r+1}")
     break
     E = (E - moved) | newpos
     dirs.rotate(-1)