Forum Programmation.autre Advent of Code 2023 : Jour 10

Posté par  . Licence CC By‑SA.
Étiquettes :
3
10
déc.
2023

--- Jour 10: Labyrinthe de tuyaux ---

Vous utilisez le deltaplane pour monter sur l'air chaud de l'île du Désert jusqu'à l'île flottante en métal. Cette île est étonnamment froide et il n'y a certainement pas de thermiques sur lesquels planer, donc vous laissez votre deltaplane derrière vous.

Vous vous promenez pendant un moment, mais vous ne trouvez ni personnes ni animaux. Cependant, vous trouvez parfois des panneaux indiquant "Sources chaudes" pointant dans une direction apparemment cohérente ; peut-être pourrez-vous trouver quelqu'un aux sources chaudes et leur demander où sont fabriquées les pièces de la machine du désert.

Le paysage ici est étranger ; même les fleurs et les arbres sont en métal. Alors que vous vous arrêtez pour admirer de l'herbe en métal, vous remarquez quelque chose de métallique qui se précipite hors de votre champ de vision périphérique et saute dans un grand tuyau ! Ça ne ressemblait à aucun animal que vous ayez jamais vu ; si vous voulez mieux le voir, vous devrez le devancer.

En scannant la zone, vous découvrez que le champ entier sur lequel vous vous tenez est densément rempli de tuyaux ; c'était difficile à dire au début car ils ont la même couleur argentée métallique que le "sol". Vous faites un rapide croquis de tous les tuyaux de surface que vous pouvez voir (votre entrée de puzzle).

Les tuyaux sont disposés dans une grille bidimensionnelle de tuiles :

  • | est un tuyau vertical reliant le nord et le sud.
  • - est un tuyau horizontal reliant l'est et l'ouest.
  • L est un coude à 90 degrés reliant le nord et l'est.
  • J est un coude à 90 degrés reliant le nord et l'ouest.
  • 7 est un coude à 90 degrés reliant le sud et l'ouest.
  • F est un coude à 90 degrés reliant le sud et l'est.
  • . est le sol ; il n'y a pas de tuyau sur cette tuile.
  • S est la position de départ de l'animal ; il y a un tuyau sur cette tuile, mais votre croquis ne montre pas la forme du tuyau.

En fonction de l'acoustique du bruit de l'animal qui se précipite, vous êtes sûr que le tuyau qui contient l'animal est une grande boucle continue.

Par exemple, voici une boucle carrée de tuyaux :

.....
.F-7.
.|.|.
.L-J.
.....

Si l'animal était entré dans cette boucle dans le coin nord-ouest, le croquis ressemblerait plutôt à ceci :

.....
.S-7.
.|.|.
.L-J.
.....

Dans le diagramme ci-dessus, la tuile S est toujours un coude F à 90 degrés : vous pouvez le dire à cause de la façon dont les tuyaux adjacents s'y connectent.

Malheureusement, il y a aussi de nombreux tuyaux qui ne sont pas connectés à la boucle ! Ce croquis montre la même boucle que ci-dessus :

-L|F7
7S-7|
L|7||
-L-J|
L|-JF

Dans le diagramme ci-dessus, vous pouvez toujours déterminer quels tuyaux forment la boucle principale : ce sont ceux qui sont connectés à S, les tuyaux auxquels ces tuyaux se connectent, les tuyaux auxquels ces tuyaux se connectent, et ainsi de suite. Chaque tuyau de la boucle principale se connecte à ses deux voisins (y compris S, qui aura exactement deux tuyaux se connectant à lui, et qui est supposé se reconnecter à ces deux tuyaux).

Voici un croquis qui contient une boucle principale légèrement plus complexe :

..F7.
.FJ|.
SJ.L7
|F--J
LJ...

Voici le même croquis d'exemple avec les tuiles de tuyaux supplémentaires, qui ne font pas partie de la boucle principale, également affichées :

7-F7-
.FJ|7
SJLL7
|F--J
LJ.LJ

Si vous voulez devancer l'animal, vous devriez trouver la tuile de la boucle qui est la plus éloignée de la position de départ. Comme l'animal est dans le tuyau, il n'est pas logique de mesurer cela par distance directe. Au lieu de cela, vous devez trouver la tuile qui prendrait le plus grand nombre d'étapes le long de la boucle pour atteindre à partir du point de départ - peu importe dans quel sens l'animal a parcouru la boucle.

Dans le premier exemple avec la boucle carrée :

.....
.S-7.
.|.|.
.L-J.
.....

Vous pouvez compter la distance de chaque tuile de la boucle par rapport au point de départ de cette manière :

.....
.012.
.1.3.
.234.
.....

Dans cet exemple, le point le plus éloigné du départ est à 4 étapes de distance.

Voici la boucle plus complexe à nouveau :

..F7.
.FJ|.
SJ.L7
|F--J
LJ...

Voici les distances pour chaque tuile de cette boucle :

..45.
.236.
01.78
14567
23...

Trouvez la seule grande boucle commençant à S. Combien d'étapes le long de la boucle faut-il pour aller de la position de départ au point le plus éloigné de la position de départ ?

  • # j'ai adoré

    Posté par  . Évalué à 2.

    Le labyrinthe de tuyaux change des labyrinthe classique.

    Cela m'a pris un peu (trop) de temps d'encoder les déplacements. Mais au final, ça se fait.

    Par contre la partie 2, je ne vois pas du tout comment procéder.

    • [^] # Re: j'ai adoré

      Posté par  . Évalué à 1.

      Pour la partie 2, cela m'a rappelé un problème que j'avais résolu sur CodingGame par remplissage de zones, mais ce n’était pas très efficace, le plus simple est de considérer uniquement les traversées de tuyaux :

      À chaque ligne on commence à l'extérieur de la boucle
      Si on traverse un tuyau | de la boucle on entre à l’intérieur de la boucle jusqu’à la prochaine traversée.
      le point un peu délicat est de considérer les autres type de traversée de tuyaux

          ligne précédente #      | |   |       |
          on entre ici     # ~~>  L-J   L-7   F-J   F-7  ~~>
                           #              |   |     | |
      dans/hors la boucle  #     0110  0111  0001  0000
      
    • [^] # Re: j'ai adoré

      Posté par  . Évalué à 2. Dernière modification le 10 décembre 2023 à 15:17.

      Avec un lib de gestion des polygone, j'ai fini par trouver pour la partie 2.
      Mais un peu l'impression de tricher et de sortir le bazooka.

      Le code pour la partie 1:

      import sys
      
      I = sys.stdin.read().splitlines()
      G = [list(l) for l in I]
      W = len(G[0])
      H = len(G)
      
      # look for S
      S = None
      for y in range(H):
          if (x := I[y].find("S")) > -1:
              S = (x,y)
              break
      
      D = {
          'u': {
              '|': ( 0,-1,'u'),
              'F': ( 1,0,'r'),
              '7': (-1,0,'l'),
          },
          'r': {
              '-': (1, 0,'r'),
              'J': (0,-1,'u'),
              '7': (0, 1,'d'),
          },
          'd': {
              '|': ( 0,1,'d'),
              'L': ( 1,0,'r'),
              'J': (-1,0,'l'),
          },
          'l': {
              '-': (-1, 0,'l'),
              'L': (0,-1,'u'),
              'F': (0, 1,'d'),
          },
      }
      
      N = 1
      x0, y0 = S
      P = (x0+1, y0, 'r')  # start at S and go right
      for _ in range(100_000):
          x, y, d = P
          N += 1
          z = G[y][x]
          if z == 'S':
              break
          dx,dy,nd = D[d].get(z)
          P = (x+dx,y+dy,nd)
      print(N//2)

      Sinon, c'est joli

      ..............................................................................╔╗.....................................................
      .......................................................................╔╗╔╗╔╗╔╝║.....................................................
      ...........................................................╔═╗.........║╚╝╚╝║╚╗╚╗....................................................
      ..................................╔╗.......................╚╗║╔╗..╔═╗..╚╗╔═╗╚╗║╔╝....................................................
      ...............................╔══╝║..................╔╗....║╚╝║.╔╝╔╝..╔╝║.╚╗║║╚═╗...................................................
      ...............................╚═╗╔╝..╔╗..╔╗..........║╚═╗..║╔═╝╔╝╔╝...╚═╝..║║║╔═╝.......╔╗..........................................
      ...............................╔═╝║...║║..║╚╗.........╚╗╔╝╔╗║╚╗╔╝╔╝╔╗.╔═╗.╔═╝║║╚═╗╔╗.....║╚╗.........................................
      ...............................╚═╗╚╗..║║╔╗║╔╝╔╗.......╔╝╚╗║╚╝╔╝║╔╝.║║╔╝╔╝╔╝╔╗║║╔═╝║║.....╚╗║...╔╗....................................
      ..............................╔═╗║╔╝╔═╝╚╝╚╝╚╗║║.....╔╗╚╗╔╝╚═╗║╔╝║╔╗║║╚╗║.╚╗║║╚╝║.╔╝╚╗..╔╗.║║.╔╗║╚╗....╔╗.............................
      ..............................╚╗║║╚╗╚════╗╔═╝║╚╗....║╚═╝║╔╗╔╝║╚╗║║╚╝║╔╝║..╚╝╚═╗╚╗╚═╗╚╗.║║╔╝╚═╝║║╔╝....║║..╔╗.........................
      ............................╔═╗║║║╔╝╔═══╗║╚╗.║╔╝....╚══╗║║║║╔╝╔╝║║╔═╝║╔╝╔╗..╔═╝╔╝╔╗╚╗╚╗║║╚═╗╔═╝║║.╔═╗╔╝║╔╗║║╔╗.......................
      .........................╔═╗╚╗║║║║╚╗║╔═╗║║╔╝╔╝╚╗.╔╗╔╗╔╗║║║║║╚╗╚╗╚╝╚╗.║╚╗║╚╗╔╝╔╗╚═╝║╔╝╔╝║╚╗.║╚╗╔╝╚╗║╔╝╚╗╚╝╚╝║║║╔╗.....................
      ..................╔╗╔══╗.╚╗╚═╝║║║║╔╝╚╝╔╝╚╝║╔╝╔╗╚╗║╚╝║║╚╝╚╝╚╝╔╝╔╝╔══╝╔╝╔╝╚╗║╚═╝╚═╗╔╝╚╗╚═╝╔╝╔╝╔╝║╔═╝║║..║╔══╗╚╝╚╝╚╗....................
      .................╔╝║╚═╗║╔╗╚══╗╚╝╚╝║╔╗.╚══╗╚╝╔╝╚═╝╚═╗║╚═╗╔═╗╔╝.╚╗║.╔═╝╔╝╔═╝╚═╗.╔╗║╚═╗╚══╗║╔╝╔╝.║║╔╗║╚╗╔╝╚═╗║╔═╗╔═╝....................
      ...............╔╗╚╗║╔╗║║║║╔═╗║╔╗╔═╝║╚══╗╔╝╔═╝╔╗╔╗╔╗║║╔╗╚╝╔╝╚╗╔╗║╚╗║╔═╝.╚══╗╔╝╔╝║║╔═╝.╔╗║║╚╗╚══╝║║║╚╗║║╔══╝╚╝.╚╝......................
      ...............║║╔╝║║║║╚╝║╚╗║╚╝║╚╗.╚═╗╔╝╚╗║╔═╝║║║║║║║║║╔╗╚╗╔╝║║║╔╝║║.╔╗.╔═╝╚╗╚╗║║║╔╗╔╝║║║╔╝╔═══╝║║╔╝╚╝╚══════╗╔╗.....................
      .........╔╗╔╗.╔╝║╚╗║║╚╝╔═╝╔╝╚═╗╚╗╚╗╔╗║╚╗╔╝╚╝╔╗║║║║╚╝║║║║║╔╝║╔╝║║╚═╝╚═╝╚╗╚═╗╔╝╔╝║║║║║╚╗╚╝╚╝╔╝.╔╗.║║╚══╗╔══════╝║╚═╗...................
      .......╔═╝╚╝║.╚╗╚═╝║╚═╗║╔╗╚╗╔═╝.╚╗║║╚╝╔╝╚╗╔═╝╚╝║╚╝╔╗║║║║║╚╗║║╔╝╚╗╔═════╝.╔╝╚╗╚╗║║║║║╔╝╔═══╝╔╗║╚═╝║╔╗╔╝╚═╗╔╗╔╗.║╔═╝.╔═╗...............
      .......╚═══╗║╔╗╚═╗╔╝╔╗║║║╚╗║╚══╗╔╝║╚╗╔╝╔═╝╚╗╔═╗╚══╝║║║║║║╔╝║║╚╗╔╝║╔╗╔╗.╔╗╚═╗╚╗║║║║║║║╔╝.╔╗.║║║╔═╗║║╚╝╔══╝║║║║╔╝║...╚╗║...............
      ...........║║║╚╗╔╝╚╗║╚╝╚╝╔╝║╔══╝╚╗╚═╝║.║╔╗╔╝║╔╝╔╗╔╗║╚╝╚╝║╚╗║║╔╝║╔╝║╚╝╚╗║╚═╗╚╗║║║║║║║║╚╗╔╝╚╗║║║║.║║╚═╗╚══╗║╚╝╚╝╔╝....║║...............
      .....╔╗╔╗╔═╝╚╝╔╝╚═╗║╚═╗╔╗╚═╝╚╗╔═╗╚══╗╚╗╚╝║║╔╝╚╗║║║║╚═══╗╚═╝╚╝╚╗║║.╚══╗║╚╗╔╝╔╝╚╝║║╚╝║║╔╝║╔╗╚╝╚╝╚╗╚╝╔╗║╔══╝║╔═══╝╔═╗..║║...............
      .╔══╗║║║║╚═══╗╚╗╔╗║║╔╗╚╝╚══╗╔╝║╔╝.╔╗║╔╝╔═╝║║╔═╝║║║║╔╗╔╗╚═════╗║║╚═╗.╔╝║╔╝╚╗║╔═╗║╚═╗║║╚╗╚╝║╔═══╗╚╗╔╝╚╝╚═╗╔╝║╔╗╔╗║╔╝╔╗║║...............
      .╚═╗╚╝╚╝╚═══╗╚╗║║║║║║║╔═╗╔═╝╚═╝╚╗╔╝╚╝╚╗╚═╗║║╚═╗║╚╝║║╚╝╚╗╔═══╗║╚╝╔═╝╔╝╔╝╚╗╔╝╚╝╔╝╚╗.║║║╔╝╔╗║║╔╗.╚═╝║╔════╝╚╗║║║║║║║.║║║╚══╗╔╗..........
      ...╚══╗╔═╗╔╗╚═╝╚╝╚╝║║║╚╗║╚══╗╔══╝╚══╗╔╝╔╗║║║╔═╝╚═╗║╚╗╔═╝╚══╗║║╔═╝╔╗║╔╝╔═╝╚╗╔╗╚═╗║╔╝╚╝╚═╝╚╝╚╝╚╗╔╗.║╚╗╔╗.╔╗║╚╝║║╚╝║╔╝╚╝╔══╝║║╔╗........
      ..╔═══╝╚╗║║╚══════╗║║║.║╚╗╔╗║╚═╗.╔╗╔╝╚╗║║║║║╚╗.╔═╝╚═╝║╔╗╔══╝║║║╔╗║║║╚═╝╔╗╔╝║╚╗╔╝║╚══╗╔═╗╔═══╗║║╚╗║╔╝║╚╗║╚╝╔╗║║╔═╝║╔══╝╔═╗║║║╚╗.......
      ..║╔╗╔═╗║╚╝.╔═════╝╚╝╚╗╚╗║║╚╝╔╗║╔╝╚╝╔╗╚╝╚╝║╚╗╚╗╚═══╗╔╝║║╚══╗║║║║║║╚╝╔╗╔╝╚╝.╚╗║╚╗╚═╗.║║.║╚╗╔╗╚╝╚╗╚╝╚╗╚╗║║╔═╝╚╝║║╔╗║║.╔╗╚╗║║╚╝╔╝.......
      ..║║╚╝.╚╝...╚╗╔═╗╔╗╔═╗╚╗║║╚╗╔╝╚╝╚═╗╔╝╚═╗╔═╝╔╝╔╝╔╗╔═╝╚╗║╚╗╔╗║╚╝╚╝║║╔═╝╚╝╔╗.╔═╝║.╚╗╔╝╔╝╚╗╚═╝║╚╗.╔╝╔══╝╔╝╚╝╚╗╔══╝║║╚╝╚╗║╚╗║╚╝╔═╝........
      ..╚╝.....╔═╗╔╝║.╚╝╚╝.╚╗║║║.║║╔╗.╔╗╚╝╔══╝╚╗╔╝╔╝.║║║╔╗╔╝╚╗║║║╚╗╔═╗║║╚══╗╔╝╚╗╚═╗║╔═╝╚╗║╔╗╚╗.╔╝╔╝╔╝╔╝.╔╗╚═╗╔═╝║╔══╝║╔══╝╚╗║║╔═╝.╔╗╔╗.....
      .........╚╗║╚═╝╔══════╝╚╝╚═╝║║╚╗║╚═╗╚══╗╔╝╚╗║╔═╝║║║╚╝╔═╝║║║.╚╝.║║║╔═╗║╚═╗║╔╗║║╚═╗╔╝╚╝╚╗╚╗╚╗║.║╔╝╔═╝║╔╗║╚═╗║║╔╗.║╚╗╔══╝║║╚═══╝╚╝╚╗....
      ..........║╚╗╔╗╚═══════╗╔╗╔╗╚╝╔╝╚═╗║╔╗╔╝╚╗╔╝║╚═╗║║╚═╗╚═╗║║║╔╗.╔╝╚╝╚╗╚╝.╔╝║║╚╝║╔╗║╚╗.╔╗╚╗╚═╝╚╗║╚╗╚═╗║║╚╝╔═╝║╚╝║╔╝╔╝╚╗╔╗║║╔════╗╔╗║....
      ..........╚╗╚╝╚════════╝║╚╝║╔╗╚╗╔╗║║║║╚╗╔╝╚╗║╔═╝║║╔═╝╔═╝╚╝╚╝║╔╝╔═══╝.╔╗╚╗║╚═╗╚╝║║╔╝╔╝╚╗║╔═══╝║╔╝╔╗║║╚═╗╚══╝╔═╝║╔╝╔╗╚╝║╚╝╚═╗..╚╝╚╝....
      ...........╚═══════════╗╚╗╔╝║╚╗║║║║║║║╔╝║╔╗║╚╝╔═╝║╚═╗╚════╗╔╝╚╗╚╗╔══╗║║╔╝║╔╗║╔╗║║╚╗╚═╗╚╝║╔╗╔╗║╚═╝║║║╔╗║╔═══╝.╔╝╚═╝╚╗╔╝╔═══╝.╔╗..╔╗...
      ..........╔═══════════╗║╔╝║╔╝╔╝║║║║║║║╚╗║║║╚╗╔╝╔╗║╔═╝╔╗.╔╗║║..║╔╝╚╗╔╝║║║╔╝║║╚╝║║║╔╝╔╗║╔═╝║║║║╚╗╔═╝║║║║║║╔═══╗╚╗╔═══╝║╔╝╔══╗.║╚╗╔╝║...
      ..........╚╗╔═╗╔╗╔═══╗║╚╝╔╝║.╚╗╚╝╚╝║║║╔╝║║║╔╝╚╗║║║╚═╗║║╔╝║║╚╗╔╝╚╗╔╝╚╗║║║╚╗║╚╗╔╝║║╚╗║║║║╔╗║║║║╔╝║╔═╝║║╚╝╚╝╔╗╔╝╔╝╚═╗╔╗║╚═╝╔╗╚╗║╔╝║╔╝...
      ........╔╗.║╚╗╚╝╚╝╔══╝╚╗.╚═╝╔╗╚═══╗║║║╚╗╚╝║║▇╔╝║║╚═╗║║║║╔╝║▇║╚╗╔╝╚═╗║║╚╝▇║║▇║║▇╚╝╔╝║║║║║║║║║╚╝╔╝╚╗╔╝║╔═══╝╚╝.║╔══╝║║║╔══╝╚╗╚╝║╔╝╚══╗.
      .......╔╝║.╚═╝╔══╗╚═══╗╚═╗╔═╝╚════╝╚╝║╔╝╔═╝╚╗╚╗║║╔╗║║║║║╚═╝╔╝╔╝║╔═╗║║╚══╗║║╔╝╚╗╔═╝╔╝║║╚╝║║║╚═╗╚╗╔╝║╔╝╚══╗╔╗╔╗║╚══╗║╚╝╚═══╗║╔╗╚╝╔═╗╔╝.
      .......╚╗║╔╗..╚═╗║╔╗╔╗╚╗╔╝╚═════╗╔╗╔╗╚╝╔╝╔╗╔╝╔╝║╚╝╚╝║║║║╔══╝╔╝╔╝║╔╝║║╔╗╔╝║║║╔╗║║╔╗╚╗║╚═╗║║╚╗╔╝▇║║╔╝║╔╗╔═╝║╚╝╚╝╔══╝║╔╗╔═══╝╚╝║╔╗╚╗║╚╗.
      ........║╚╝║.╔═╗║║║╚╝╚═╝╚╗╔════╗╚╝╚╝╚╗▇╚╗║║║▇╚╗╚═╗╔═╝║╚╝╚╗╔╗║▇╚╗║╚╗║║║╚╝▇╚╝║║║║║║╚╗║╚╗╔╝║║╔╝╚╗╔╝║╚═╝║╚╝╔╗╚╗╔══╝╔╗.║║║╚═════╗║║╚═╝╚═╝.
      ........╚═╗╚╗╚╗║║╚╝╔════╗║╚══╗╔╝╔═╗╔╗╚═╗║║║╚═╗║╔╗║║╔╗╚╗╔═╝║║╚═╗║║▇║║║╚╗╔═══╝║╚╝║║╔╝╚╗╚╝▇║║╚╗╔╝╚═╝▇╔═╝╔═╝╚═╝║╔╗╔╝╚═╝║╚════╗╔╝║╚═╗.....
      ........╔╗╚╗╚═╝╚╝╔╗║╔═══╝╚═╗╔╝╚═╝╔╝║║╔╗║╚╝║╔═╝║║║║║║╚╗║║╔═╝║╔═╝║║╔╝║╚═╝╚╗╔╗╔╝╔═╝║╚══╝╔══╝╚╗║║╔═══╗╚══╝╔═══╗╚╝║║╔═══╝.╔╗╔╗╚╝.╚══╝.....
      ........║║.╚════╗║║║╚══╗╔═╗║╚═══╗╚═╝╚╝╚╝╔╗║╚═╗╚╝║║║║╔╝║║║╔═╝╚═╗╚╝╚╗╚═╗▇╔╝║║║╔╝╔╗╚══╗▇╚═══╗║╚╝╚══╗╚╗▇╔╗╚══╗║╔╗╚╝╚═════╝╚╝╚═══╗.╔═╗....
      .....╔══╝║╔╗╔═══╝║╚╝╔══╝║╔╝╚╗╔══╝╔══════╝║╚═╗╚═╗║║║║║╔╝║║║╔╗╔╗╚╗▇╔╝╔╗╚╗╚╗║║║║╔╝╚╗╔═╝╔═╗▇╔╝╚═╗╔╗▇╚╗╚═╝╚═══╝║║║╔═╗╔╗╔╗╔═╗╔╗╔═╗║╔╝╔╝....
      .....╚╗╔╗╚╝╚╝╔╗╔═╝╔═╝╔══╝╚═╗║╚═══╝╔╗╔═╗╔╗╚╗▇║╔╗║╚╝║║║║╔╝║║║╚╝╚╗╚╗║╔╝╚╗╚╗║║║║║║▇╔╝╚╗▇║╔╝╔╝╔═╗║║╚══╝╔═══╗╔╗.║║╚╝.║║╚╝║╚╗╚╝╚╝.╚╝╚╗║.....
      ......╚╝╚═══╗║║║╔═╝╔╗╚╗╔═══╝╚══╗╔═╝╚╝▇╚╝║╔╝╔╝║║╚═╗║║║║╚╗║╚╝▇╔═╝╔╝║╚╗▇╚╗║║║╚╝║║╔╝╔╗╚═╝║▇╚╗╚╗║║╚══╗╔╝▇╔╗║║╚╗║╚══╗║╚═╗╚╗╚╗╔╗╔╗╔╗╔╝╚═╗...
      .......╔══╗.╚╝╚╝╚══╝╚═╝╚══════╗║╚╗╔╗╔══╗║╚╗╚╗║╚╗╔╝╚╝║║╔╝║╔╗╔╝╔╗╚╗║╔╝╔═╝║╚╝╔═╝║║╔╝║╔═╗╚╗▇╚═╝╚╝▇╔═╝║╔═╝╚╝║╔╝╚═══╝║╔═╝.╚╗╚╝╚╝║║║╚╗╔═╝...
      .......╚═╗╚═════╗.╔╗╔╗╔═══════╝╚═╝║║║╔═╝╚╗║╔╝╚╗║╚══╗║║╚═╝║╚╝╔╝╚╗║╚╝╔╝╔╗╚═╗╚═╗║║║╔╝╚╗╚╗╚══╗▇╔═╗╚═╗║╚════╝╚════╗.╚╝╔══╗║╔╗╔═╝║╚═╝║.....
      ......╔╗╔╝╔══╗╔╗╚═╝║║║╚═╗╔══╗╔══╗▇║╚╝║▇╔╗╚╝╚══╝║╔══╝╚╝╔══╝╔╗╚═╗╚╝▇╔╝╔╝╚══╝╔═╝║║║║╔╗╚╗║╔═╗╚╗╚╗║╔╗╚╝╔╗╔╗╔╗╔═╗╔╗╚═╗.║╔═╝║║║╚══╝╔═╗╚╗....
      .....╔╝╚╝╔╝╔═╝║╚╗╔╗╚╝╚═╗╚╝╔╗╚╝╔╗╚═╝╔╗╚═╝║╔═╗╔═╗╚╝╔═══╗╚╗╔╗║║╔╗╚╗╔╗╚╗╚═══╗▇║╔═╝╚╝╚╝║╔╝║╚╗║╔╝╔╝╚╝╚══╝╚╝╚╝╚╝╔╝║║╔═╝╔╝╚═╗╚╝╚═╗╔╗║.║╔╝....
      .....╚╗╔╗║╔╝╔╗║.╚╝╚═══╗╚══╝║╔═╝║╔╗╔╝╚═══╝╚╗║║╔╝╔╗╚╗╔═╝╔╝║║║╚╝╚╗╚╝║╔╝╔╗╔═╝╔╝║╔═════╝╚╗║╔╝║╚╗╚╗╔╗╔╗╔══╗╔══╗╚═╝╚╝╔╗║╔══╝╔══╗║║║╚╗║║.....
      ......╚╝║║╚═╝╚╝╔╗╔═══╗╚═══╗║╚═╗╚╝╚╝▇╔╗╔╗╔╗║╚╝╚╗║║╔╝╚═╗╚╗║║╚╗▇╔╝╔╗║╚╗║║╚═╗╚╗║╚╗╔╗╔╗╔═╝╚╝▇╚╗╚╗╚╝╚╝╚╝╔╗╚╝╔═╝╔╗╔╗╔╝╚╝╚╗╔╗║╔═╝║║║╔╝╚╝.....
      ........╚╝.╔╗╔═╝║╚══╗║╔╗╔╗║║╔╗╚═════╝╚╝╚╝╚╝╔═╗╚╝╚╝╔╗╔╝╔╝║╚═╝╔╝╔╝║╚╗║║╚╗╔╝╔╝║╔╝║╚╝║╚═════╗╚╗║╔═════╝╚══╝.╔╝╚╝╚╝╔═══╝║║║╚═╗╚╝╚╝........
      ........╔═╗║║╚═╗║╔╗╔╝╚╝╚╝╚╝╚╝║╔╗╔╗╔╗╔╗╔╗╔══╝▇╚╗╔╗╔╝║║▇╚═╝╔══╝╔╝╔╝╔╝║║╔╝╚╗║╔╝╚═╝╔═╝╔╗╔╗╔╗╚╗║║║╔═════════╗╚╗╔══╗╚════╝╚╝╔╗╚══╗╔╗.......
      ........╚╗╚╝╚══╝╚╝║╚════════╗╚╝╚╝╚╝╚╝╚╝║╚═╗╔═╗║║║║▇╚╝╔══╗║╔═╗║╔╝╔╝╔╝║║╔╗║║║╔╗╔╗╚╗╔╝║║╚╝╚╗║║║╚╝╔════════╝╔╝╚╗.║╔╗╔═╗╔═╗║║╔═╗╚╝╚═╗.....
      .........╚╗╔╗╔═╗╔╗╚═════════╝╔═════╗╔═╗╚╗╔╝║╔╝╚╝║╚═══╝╔═╝║║╔╝║║╔╝▇║╔╝║║║║╚╝║║║║╔╝╚╗║╚══╗║║║║╔╗╚═════════╝╔╗╚╗║║║╚╗║║╔╝║║╚╗║╔═══╝.....
      ..........║║║║.╚╝╚═╗╔═╗╔═╗╔╗╔╝╔╗╔══╝║╔╝▇╚╝╔╝╚╗╔╗║╔╗╔═╗║╔╗╚╝║╔╝║╚═╗║║▇╚╝║║╔═╝╚╝╚╝╔╗║║╔═╗║║║╚╝║╚╗╔═══════╗╔╝╚═╝╚╝╚═╝║║╚╗║╚═╝║╚═══╗.....
      ..........╚╝╚╝.╔╗.╔╝╚╗╚╝.╚╝╚╝╔╝╚╝╔╗▇║║╔═══╝╔╗╚╝║║║╚╝╔╝╚╝╚═╗║║▇║╔═╝╚╝▇▇╔╝║╚╗╔═╗╔╗║║║║╚╗║║╚╝╔╗╚╗║╚══════╗║╚═════╗╔╗╔╝║╔╝╚╗╔╗╚═══╗║.....
      ...........╔╗╔═╝╚═╝╔═╝╔══╗╔╗.╚═══╝╚═╝╚╝╔═╗╔╝║╔╗║║╚═╗╚╗╔═╗╔╝║║╔╝║▇▇▇▇▇▇╚═╝▇║║╔╝║║║╚╝╚╗║╚╝╔═╝╚═╝╚╗▇╔╗▇╔╗║║╔═╗╔═╗╚╝║║╔╝║╔╗╚╝╚═══╗║║.....
      ..........╔╝║╚══╗╔╗║╔╗╚═╗╚╝╚═══════════╝▇╚╝▇║║║║║╔╗╚╗║║╔╝╚╗╚╝╚╗╚═╗▇▇▇▇▇▇▇╔╝║╚╗║║║╔╗╔╝╚╗▇╚═════╗║╔╝╚╗║╚╝╚╝╔╝╚╗║╔═╝╚╝.║║║╔╗╔═══╝╚╝.....
      ..........╚╗╚═══╝║╚╝║╚╗.╚╗╔╗╔╗╔════════╗╔══╗║║╚╝╚╝╚╗║║║╚╗╔╝▇▇▇║╔╗║▇▇▇▇▇▇▇╚═╝▇║║╚╝║║║╔╗║╔══╗╔╗╔╝╚╝╔╗╚╝╔╗╔╗╚╗╔╝║╚════╗║║║║║╚═══╗.......
      .........╔╗╚═════╝.╔╝╔╝╔╗╚╝║║║║╔═╗╔══╗╔╝║╔═╝║╚════╗║║╚╝╔╝║▇▇▇▇║║╚╝▇▇▇▇▇▇▇▇╔══╝╚╗╔╝╚╝║╚╝╚═╗║║║╚══╗║╚═╗║╚╝╚╗╚╝.╚═╗╔══╝╚╝║║║╔═╗╔╝.......
      .........║╚═══╗.╔═╗╚╗╚═╝╚══╝║╚╝╚╗╚╝╔╗╚╝╔╝╚═╗╚═╗╔╗╔╝║╚╗▇╚═╝▇▇▇▇╚╝▇▇▇▇▇▇▇▇▇▇╚═╗╔═╝╚═══╝╔═══╝╚╝╚═╗▇╚╝╔╗╚╝╔╗╔╝╔╗╔╗.╚╝╔═╗╔╗╚╝║╚╗╚╝╔╗......
      .........╚═══╗╚╗╚╗╚╗╚═══╗╔╗╔╝.╔╗╚══╝╚╗╔╝╔═╗╚═╗╚╝╚╝▇╚═╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚╝╔╗╔══╗▇╚══╗╔═╗╔╗╚═══╝╚══╝╚╝╔╝╚╝║╔╗.╚╗║║╚═╗╚╗╚══╝╚═╗....
      ........╔╗╔═╗╚╗║╔╝╔╝.╔╗.╚╝╚╝╔╗║║╔═══╗╚╝╔╝▇╚══╝╔╗╔╗╔╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔╝╚╝╔╗╚╗▇╔╗║║╔╝║╚════╗╔╗╔══╗║╔═╗╚╝╚══╝╚╝╔╗║╔╝╔═╗╔═╗║....
      .......╔╝║╚╗║.║║╚╗╚╗╔╝╚╗.╔══╝╚╝╚╝╔╗▇╚╗╔╝▇╔════╝╚╝╚╝╚╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚══╗║╚╗╚╗║║╚╝╚═╝╔════╝║╚╝╔═╝║║.╚══╗╔══╗╔╝╚╝╚╗╚╗╚╝.╚╝....
      .......╚╗║╔╝╚═╝╚╗║╔╝╚═╗╚═╝╔╗╔════╝╚═╗║╚══╝╔═╗╔═╗╔═══╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔╝║▇╚╗║║╚═╗▇╔╗╚═══╗╔╝╔═╝╔╗║╚═╗╔╗╚╝..╚╝..╔╗║╔╝.........
      ...╔═╗╔═╝║╚══╗╔╗╚╝╚═══╝╔══╝╚╝╔════╗╔╝║╔══╗╚╗║╚╗╚╝╔═╗╔╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚╗║╔═╝╚╝╔═╝╔╝╚╗▇╔╗╚╝▇╚══╝║║╔═╝║║.╔╗╔╗╔╗.║║╚╝.╔╗.......
      ...╚╗║╚═╗╚╗╔╗╚╝╚═╗╔═╗╔╗║╔═══╗╚═══╗╚╝▇╚╝╔╗╚═╝╚═╝╔═╝╔╝║║▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚╝╚═╗╔╗╚══╝╔╗╚═╝╚══╗╔═══╝║╚══╝║╔╝╚╝╚╝╚╗║╚╗╔═╝╚══╗....
      .╔══╝╚═╗╚╗║║║.╔═╗╚╝.╚╝╚╝╚══╗╚════╝▇╔══╗║╚══╗▇╔╗╚╗╔╝╔╝╚═╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔═╗╔╗╚╝╚═══╗║╚═════╗║╚════╝╔╗╔═╝║╔═╗╔╗╔╝║╔╝╚╗╔═══╝....
      .╚╗╔╗╔╗╚═╝╚╝╚╗╚╗╚═╗╔═╗╔╗╔╗╔╝╔╗╔════╝╔═╝║╔══╝╔╝║╔╝╚═╝╔══╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔╗▇▇▇╚╗╚╝╚══════╝║╔═════╝║╔╗╔═══╝║╚══╝╚╗╚╝╚╝.║╚═╗║║╔═══╗...
      ..╚╝╚╝╚═╗╔╗╔╗╚═╝╔╗╚╝╔╝║║║║╚═╝║║.╔══╗╚═╗║╚╗╔╗╚╗╚╝╔╗╔╗╚══╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇║║▇╔╗▇║╔══════╗╔═╝╚═════╗╚╝╚╝.╔╗.╚════╗╚╗╔╗╔╗║╔═╝║╚╝╔══╝...
      .....╔╗╔╝║╚╝╚╗╔╗║║╔╗╚═╝╚╝╚╗╔═╝║╔╝╔╗╚══╝║╔╝║║╔╝╔═╝╚╝╚═╗╔╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇║╚═╝╚╗╚╝▇╔═══╗║║╔═══╗╔═╗╚╗╔══╗║╚╗.╔╗╔╗╚╗╚╝║║║║╚═╗║╔╗╚╗.....
      ....╔╝╚╝╔╝╔╗╔╝║╚╝╚╝╚══╗╔═╗╚╝╔╗║╚═╝╚════╝╚╗║║╚╗╚═════╗║╚╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚═══╗║▇╔╗╚══╗╚╝║╚══╗║╚╗║╔╝║╔═╝║╔╝╔╝╚╝╚╗╚══╝║║║╔═╝║║╚═╝.....
      ....╚╗╔╗║╔╝╚╝╔╝╔══════╝║.╚╗╔╝╚╝.╔╗╔══════╝║║╔╝╔╗╔╗╔═╝╚═╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔══╝╚╗║╚═╗╔╝╔═╝╔══╝╚═╝╚╝╔╝╚══╝╚═╝╔╗╔╗╚═══╗║║║╚══╝╚╗.......
      ....╔╝║║║╚╗╔╗╚╗╚═══════╝╔╗╚╝╔═══╝╚╝▇╔╗╔╗▇╔╝╚╝╔╝║║║╚═╗▇╔═══╗▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╚═══╗║╚╗╔╝╚═╝╔╗╚══╗╔═╗╔═╝▇╔══╗╔══╝╚╝║╔╗╔╗╚╝╚╝╔╗╔══╝╔═╗....
      ....╚╗║╚╝.╚╝╚═╝╔════════╝╚═╗╚═══════╝╚╝╚═╝╔╗╔╝╔╝║╚══╝╔╝╔══╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔══╗║╚═╝╚════╝╚═══╝║╔╝║╔═╗╚═╗║╚═╗╔╗.╚╝║║║╔═══╝║╚═══╝╔╝....
      .....║╚╗╔╗╔═╗╔╗╚╗╔═╗╔╗╔═╗╔═╝╔════╗╔════╗╔╗║╚╝▇╚╗╚═╗▇╔╝╔╝▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇╔═╝╔╗╚╝╔╗╔╗╔╗╔═════╗╔╝╚╗║╚╗╚══╝╚═╗╚╝╚══╗╚╝╚╝╔══╗║╔═╗╔═╝.....
      .....╚═╝║║╚╗║║╚╗╚╝.╚╝╚╝╔╝║╔╗╚═══╗║╚══╗▇╚╝║╚══╗╔╝╔╗╚═╝╔╝▇▇╔╗▇▇▇▇▇╔═╗▇▇▇▇╔╗╚══╝╚╗╔╝╚╝╚╝╚╝╔═══╗╚╝╔═╝║▇╚═════╗╚╗╔╗╔╗╚════╝╔═╝║╚╗╚╝.......
      ......╔═╝╚═╝║╚╗║.╔╗.╔╗.╚╗║║║╔═══╝╚══╗╚══╗╚╗╔═╝╚╗║║╔╗╔╝╔╗╔╝╚═╗▇▇▇╚╗╚╗▇▇╔╝║▇▇╔╗▇║║╔══╗╔══╝╔╗╔╝╔╗╚══╝╔══════╝.╚╝╚╝╚════╗╔╝╔╗╚═╝.........
      ...╔═╗╚════╗╚═╝╚═╝╚═╝╚══╝╚╝║║╔════╗▇╚═══╝▇║╚══╗╚╝║║╚╝▇║║║╔══╝▇▇╔╗║╔╝▇▇╚╗╚╗╔╝╚╗║║╚═╗║╚═══╝║╚═╝║▇╔╗▇╚════════╗╔═════╗.╚╝╔╝╚═╗..........
      ...╚╗║.╔╗╔═╝╔═══════════╗╔╗║╚╝╔╗╔╗╚═════╗╔╝╔═╗╚═╗║║╔══╝║║╚═╗▇▇╔╝║║╚╗▇╔╗║╔╝╚╗╔╝╚╝╔╗║║╔╗▇╔╗╚══╗╚═╝║╔╗╔═══╗╔══╝╚╗╔═══╝╔╗.║╔═╗╚╗.........
      ...╔╝╚═╝╚╝╔╗║╔══════╗╔╗.╚╝║║.╔╝╚╝╚══╗╔═╗║╚╗╚╗╚═╗║╚╝╚╗╔═╝║╔═╝▇▇╚╗║║╔╝╔╝╚╝╚╗▇║╚═╗╔╝╚╝║║╚╗║╚═══╝╔═╗║║║╚══╗╚╝╔╗╔╗║║╔══╗║║╔╝╚╗╚═╝.........
      ...╚══╗╔═╗║║║╚═╗╔╗╔╗╚╝╚═══╝╚╗║╔════╗║╚╗╚╝▇╚╗╚╗▇╚╝╔══╝║╔╗║╚══╗╔═╝╚╝║╔╝╔═══╝╔╝╔═╝╚╗╔╗╚╝╔╝║╔═══╗║╔╝╚╝╚═══╝╔╗║╚╝╚╝║║╔═╝║╚╝╔═╝............
      ....╔═╝╚╗╚╝╚╝╔╗║║╚╝╚═╗╔╗╔══╗║╚╝.╔╗╔╝╚═╝╔══╗╚═╝╔═╗╚══╗╚╝║║╔╗╔╝╚═══╗║╚╗╚╗╔╗▇╚╗╚══╗╚╝╚═╗╚╗╚╝╔╗▇╚╝╚═╗╔╗╔╗╔═╝╚╝╔══╗╚╝╚╗╔╝╔╗╚═╗............
      ..╔╗║╔══╝╔═══╝╚╝║╔══╗╚╝╚╝╔═╝╚╗╔═╝╚╝▇╔╗▇║╔═╝╔╗▇║╔╝▇╔╗║╔═╝║║╚╝▇╔═╗╔╝╚╗╚╗╚╝╚╗╔╝╔══╝╔╗╔╗║╔╝▇╔╝╚═╗╔══╝║╚╝╚╝╔╗╔╗╚╗.╚══╗╚╝╔╝╚╗╔╝............
      ..║╚╝║╔══╝╔═╗╔═╗║╚═╗║.╔╗.╚══╗║╚════╗║╚╗║║╔╗║║╔╝╚╗╔╝║║╚═╗║╚═╗▇╚╗║╚═╗║▇╚═╗╔╝║╔╝▇╔╗║╚╝║║║╔╗╚╗╔═╝╚══╗║╔═══╝╚╝╚╗╚═══╗╚╗╔╝╔╗╚╝╔╗.╔╗........
      ╔═╝╔╗║╚═══╝.║║.╚╝.╔╝╚═╝╚════╝╚═════╝║╔╝║╚╝╚╝╚╝╔═╝╚╗║║╔═╝║╔═╝▇╔╝║╔═╝║╔╗╔╝╚═╝╚═╗║║╚═╗║║╚╝╚═╝╚╗╔╗╔╗╚╝╚══════╗╚╗╔══╝.╚╝.║╚══╝╚╗║╚═╗......
      ║╔╗║║╚╗.╔═══╝╚╗.╔═╝╔╗╔╗╔╗╔══╗╔══╗╔══╝╚╗║╔╗╔═╗╔╝╔═╗║╚╝║╔╗║║╔╗╔╝╔╝╚╗╔╝║║╚╗╔╗╔═╗║║╚═╗║║╚╗╔╗╔═╗╚╝╚╝╚╗╔╗╔╗╔═╗╔╝╔╝╚═══════╝╔═╗╔╗║║╔═╝......
      ║║╚╝╚╗║.╚╗╔═╗╔╝╔╝╔╗║║║╚╝║║╔═╝╚═╗╚╝╔╗╔╗╚╝║╚╝▇╚╝▇╚╗║╚╗╔╝║║║║║║║╔╝╔═╝╚╗║╚╗╚╝║╚╗╚╝╚═╗╚╝╚╗║║║║╔╝╔═╗╔╗╚╝║║║╚╗║╚╗╚═╗╔═╗╔════╝.║║║╚╝╚╗.......
      ╚╝...║║..║║╔╝║.╚═╝╚╝║║╔╗╚╝╚╗╔══╝╔═╝╚╝╚╗╔╝▇╔╗▇╔╗╔╝╚═╝╚╗║║║║║║║╚╗╚══╗║║╔╝╔═╝╔╝▇╔╗▇║╔╗╔╝║║╚╝╚╗║▇║║║╔╗╚╝╚═╝╚═╝╔╗║║╔╝╚═══╗╔╗║║║╔══╝...╔╗..
      .....╚╝..╚╝║╔╝╔══╗╔═╝╚╝║╔╗╔╝║╔══╝╔╗╔═╗║╚══╝╚╗║║╚╗╔══╗╚╝║║║║║╚╗╚══╗║║║╚╗╚╗╔╝╔╗║╚╗╚╝║╚╗╚╝╔══╝║╔╝║║║╚═╗╔═════╝║║║║╔╗╔══╝║║╚╝╚╝╔╗.╔╗╔╝║..
      ...........╚╝╔╝╔╗╚╝╔══╗║║╚╝╔╝╚═══╝╚╝╔╝║╔╗╔═╗╚╝║▇╚╝▇╔╝╔═╝║║║║▇╚╗╔═╝║║╚╗║╔╝║▇║║╚╗║╔╗║╔╝╔╗╚╗╔╗║╚═╝║║╔═╝╚╗╔════╝╚╝╚╝║╚═══╝╚════╝╚╗║║║╔╝..
      .............╚═╝╚═╗║╔═╝║╚══╝╔╗.╔═╗╔╗║╔╝║╚╝▇║╔═╝╔╗▇╔╝╔╝╔╗║╚╝║╔═╝╚═╗║╚╗║║╚╗╚═╝╚╗║║║║║║╔╝╚╗╚╝╚╝╔╗▇╚╝╚═══╝╚═╗.╔══╗╔╗╚═════╗╔╗╔╗╔═╝║║║║╔╗.
      ..........╔╗╔═════╝║╚══╝.╔╗╔╝╚╗╚╗╚╝╚╝╚╗╚══╗╚╝╔╗║║╔╝╔╝▇║║║╔═╝╚╗╔══╝╚╗║║╚╗╚╗╔══╝║╚╝╚╝╚╝╔═╝╔╗╔╗║╚═════════╗╚═╝╔═╝║║╔╗╔╗╔╗╚╝╚╝╚╝.╔╝╚╝╚╝╚╗
      .......╔═╗║║╚══════╝.╔═══╝╚╝╔╗╚═╝╔╗╔═╗╚═══╝╔═╝╚╝╚╝╔╝╔╗║║║╚╗╔═╝╚╗▇╔╗║║╚╗╚═╝║▇╔╗║╔╗╔═╗╔╝╔╗║╚╝║║╔═╗╔═╗╔══╗║╔═╗╚╗╔╝║║╚╝╚╝╚═══╗.╔╗╚╗╔══╗╔╝
      .......╚╗╚╝║╔╗╔═╗╔══╗║╔═════╝╚═══╝╚╝╔╝╔╗╔╗▇╚═╗╔══╗╚╗║║║║║╔╝╚╗╔╗╚╗║╚╝╚╗╚╗╔╗╚═╝║║║║║╔╝╚╗║║╚╗╔╝╚╝╔╝║╔╝╚╗╔╝╚╝.╚═╝║╔╝║╔═══════╝╔╝╚═╝╚╗.║║.
      ........╚═╗║║║╚╗║╚═╗║╚╝╔╗╔══════════╝╔╝║║╚═╗▇╚╝╔╗╚╗╚╝╚╝╚╝║╔╗╚╝╚╗║║╔══╝▇╚╝╚╗╔═╝╚╝╚╝╚╗╔╝║╚╗║╚══╗║╔╝╚╗╔╝╚═══╗╔╗.║╚═╝╚═╗╔════╗║╔════╝.║╚╗
      ........╔═╝╚╝╚╗║╚══╝╚╗╔╝║╚═══════════╝╔╝║╔═╝╔═╗║║▇║╔════╗║║║╔╗▇║║║║▇╔╗╔╗╔═╝║╔╗╔╗▇╔╗║╚╗╚╗║║╔══╝╚╝╔╗╚╝╔╗╔══╝║╚═╝╔╗╔╗╔╝║╔═══╝║╚╗╔═╗╔╗╚═╝
      ........╚════╗║╚════╗║╚╗╚═══╗.╔══════╗╚╗║║╔╗╚╗╚╝║╔╝╚╗▇╔╗╚╝║║║╚═╝╚╝╚╗║║║║╚═╗║║║║╚╗║╚╝╔╝╔╝╚╝╚╗▇╔╗╔╝║╔═╝╚╝.╔╗╚╗╔═╝╚╝╚╝.║║╔╗╔╗║╔╝║╔╝║║...
      ........╔╗╔══╝╚═╗╔══╝╚═╝╔══╗╚╗╚═╗╔══╗║╔╝║║║╚╗╚═╗║╚╗╔╝╔╝║╔╗║║╚═══╗╔═╝║╚╝║╔═╝╚╝║╚╗║╚═╗║╔╝╔═══╝╔╝║║╔╝╚═════╝╚═╝╚═══════╝╚╝╚╝╚╝╚╗║║╔╝╚══╗
      ......╔╗║║╚════╗║╚══════╝╔╗╚╗╚═╗╚╝╔═╝╚╝╔╝╚╝╔╝▇╔╝╚═╝╚═╝╔╝║║║╚═╗╔═╝║╔═╝╔═╝╚══╗╔╝╔╝║▇╔╝║║╔╝╔══╗╚╗║║║╔═══════════╗╔═╗╔╗╔╗╔═╗╔╗╔╗╚╝╚╝╔═╗╔╝
      .....╔╝╚╝╚═════╝╚════════╝╚═╝╔╗╚═╗╚═╗╔╗╚═╗╔╝╔╗╚══╗╔═══╝╔╝║╚═╗║╚═╗║╚╗╔╝▇╔╗╔╗║║▇╚╗║╔╝╔╝║╚╗║╔═╝╔╝║║║╚══╗╔══════╗║║.╚╝║║╚╝.║║║║║╔╗╔═╝.╚╝.
      .....╚═══╗╔╗╔╗╔═╗╔╗╔╗╔═╗╔═╗╔═╝╚═╗╚══╝║║╔╗║║╔╝╚╗╔╗║╚╗╔═╗╚╗╚═╗║╚╗╔╝║╔╝║╔╗║╚╝║║║╔╗║║╚╗╚╗║╔╝║║╔╗╚╗╚╝╚╗╔╗╚╝╔═╗╔══╝╚╝╔═╗║╚══╗╚╝║║╚╝╚╝╔═╗...
      ......╔═╗╚╝╚╝╚╝╔╝║║║╚╝╔╝║.╚╝╔╗.╔╝╔╗╔╗║║║║║║╚╗╔╝║║║╔╝║╔╝▇╚═╗║║╔╝╚╗║║╔╝║║╚═╗║║║║║║║▇╚╗║║║▇║║║║▇║╔══╝║║╔╗╚╗║╚═════╝╔╝╚╗╔╗╚═╗║╚════╝╔╝...
      .╔╗╔══╝╔╝.╔═══╗╚╗║║║╔╗╚═╝╔╗╔╝╚═╝╔╝╚╝║║╚╝╚╝╚╗║║╔╝║║║╔╝║╔╗╔╗║║║╚╗╔╝║║║╔╝╚╗╔╝║║╚╝║║║╔╗║║║║╔╝║║║╔╝╚╗╔╗║╚╝║╔╝╚═╗╔╗╔══╝╔╗╚╝║╔═╝╚╗╔╗╔═╗╚╗...
      .║╚╝╔═╗║╔╗╚══╗║.╚╝╚╝║╚╗╔╗║╚╝╔═══╝.╔═╝╚═╗.╔╗║║║║.║║║║╔╝║║║║║║╚╗║║.║║╚╝╔═╝║.╚╝╔═╝║║║║║║║║║.║║║║╔═╝║╚╝╔═╝╚══╗║║║╚═══╝╚═╗║╚══╗║║║╚╗║╔╝...
      .╚╗╔╝╔╝╚╝╚╗╔╗║║╔══╗╔╝╔╝║╚╝╔╗║╔════╝╔╗╔╗╚╗║║╚╝║╚╗║║║║║╔╝║║║║╚╗║║║╔╝╚═╗║╔╗╚══╗╚═╗║║║║║║║║╚╗║║║║╚═╗╚═╗╚═╗╔╗╔╝╚╝╚╗╔╗╔╗╔═╝╚═══╝╚╝╚═╝╚╝....
      ..╚╝.╚══╗╔╝║║║║╚╗╔╝╚╗╚╗╚══╝║║║╔═══╗║║║║╔╝║╚══╝╔╝╚╝╚╝║╚╗║║║╚╗║║║║╚╗╔╗║║║╚╗╔╗╚╗╔╝║╚╝║║╚╝║╔╝║║╚╝╔═╝╔═╝.╔╝║║╚╗╔╗.║║╚╝║╚═══╗.╔════╗.......
      ...╔══╗╔╝║╔╝║║╚╗║╚═╗║╔╝╔═══╝║║╚═╗╔╝║╚╝║║.║╔╗╔╗╚══╗.╔╝╔╝║║╚╗║║║║╚╗║║║║║╚╗╚╝║╔╝╚╗╚╗╔╝╚╗╔╝║╔╝╚═╗╚═╗╚╗.╔╝╔╝╚╗╚╝╚╗║╚╗.╚═╗╔╗╚═╝╔╗╔═╝.......
      ...╚═╗╚╝╔╝╚╗╚╝╔╝╚═╗║║╚═╝╔╗╔═╝║╔╗║╚╗╚═╗╚╝╔╝║║║║╔══╝╔╝╔╝╔╝║╔╝║╚╝║╔╝╚╝║║║╔╝╔═╝║╔═╝╔╝║╔╗║╚╗║╚╗╔═╝╔═╝╔╝╔╝╔╝╔═╝╔══╝╚╗╚╗╔╗╚╝║╔╗╔╝║╚══╗......
      .....╚═╗║╔╗S╗╔╝..╔╝╚╝╔═╗║║║╔═╝║║╚╗╚═╗╚╗╔╝╔╝║║║╚═╗╔╝╔╝╔╝╔╝║╔╝╔═╝║╔╗╔╝║║╚╗╚╗╔╝║╔╗║.╚╝║╚╗╚╝.║╚╗╔╝╔╗╚╗║╔╝.║╔╗╚═══╗╚╗╚╝╚═╗╚╝╚╝.║╔══╝......
      ....╔══╝╚╝╚═╝║╔╗╔╝╔═╗╚╗║║║║╚╗╔╝╚╗║╔═╝╔╝╚═╝.╚╝╚╗╔╝║╔╝.║╔╝╔╝╚╗║╔╗╚╝║╚╗║║╔╝.║║╔╝║║║╔╗.║╔╝╔══╝╔╝╚╗║║╔╝║╚═╗╚╝╚═╗╔═╝╔╝╔╗╔╗╚═══╗.╚╝.........
      ....║╔╗╔╗╔╗╔╗╚╝╚╝╔╝.║╔╝╚╝║║╔╝║╔╗╚╝║╔╗╚═════╗.╔╝║╔╝║╔═╝║.╚╗╔╝╚╝║╔╗╚╗║║║╚═╗╚╝║╔╝║╚╝╚╗╚╝.╚══╗╚═╗║║║╚╗║╔╗╚═══╗║╚═╗╚═╝║║╚╗╔══╝╔╗.╔╗.......
      ....╚╝╚╝║║║║╚╗╔═╗╚╗╔╝╚══╗╚╝╚╗╚╝╚═╗╚╝╚╗╔═╗╔╗║╔╝╔╝║╔╝║╔╗║╔═╝╚═╗╔╝║║╔╝║║╚╗╔╝╔╗║╚╗╚╗╔╗╚══╗╔══╝╔═╝║║║╔╝║║╚╗╔═╗║║╔═╝╔═╗╚╝╔╝╚═══╝╚═╝╚═╗.....
      ......╔═╝║╚╝.║╚╗╚╗║╚╗╔═╗║╔══╝╔╗╔╗║╔══╝║.║║║║╚╗╚╗║╚╗║║╚╝╚╗╔═╗║╚═╝║║.║║╔╝║.║╚╝╔╝╔╝║╚╗╔╗║╚╗╔╗║.╔╝║╚╝.║║╔╝║.╚╝║║╔╗║╔╝╔╗╚╗╔╗╔══╗╔╗╔═╝.....
      ......║╔╗╚╗╔╗║╔╝╔╝╚╗║╚╗╚╝╚══╗║╚╝║║╚╗╔╗╚╗║║║╚╗╚╗║║╔╝║║╔═╗║║.╚╝╔══╝║╔╝║╚╗║╔╝╔╗║.╚╗╚╗║║║║.║║║╚╗╚╗╚══╗║║╚╗║╔══╝╚╝╚╝╚═╝║.╚╝╚╝..║║╚╝.......
      .....╔╝║╚╗║║╚╝╚╗╚╗╔╝║╔╝╔═╗╔╗║╚╗╔╝║.╚╝║╔╝╚╝║╔╝╔╝║║╚╗║║╚╗╚╝╚══╗╚══╗║╚═╝.╚╝╚╗║║╚╗╔╝╔╝║║╚╝╔╝║╚╗╚╗╚╗╔╗║╚╝.║║╚╗╔╗╔═╗╔╗╔╗╚═════╗.╚╝.........
      .╔╗.╔╝╔╝.║║╚╗╔═╝╔╝╚╗║╚╗╚╗╚╝╚╝╔╝╚╗║╔══╝╚══╗╚╝╔╝╔╝╚╗║║║╔╝╔═╗╔╗╚╗.╔╝╚═╗╔════╝║╚╗║╚╗║╔╝╚═╗╚╗║╔╝╔╝╔╝║╚╝.╔═╝║╔╝║║╚╗║║╚╝║╔╗╔═══╝............
      .║╚═╝╔╝..╚╝.╚╝╔═╝╔═╝║╔╝.╚╗╔╗╔╝╔╗║║║╔═╗╔══╝╔═╝╔╝..╚╝╚╝╚═╝╔╝║║╔╝╔╝╔╗╔╝╚═══╗╔╝.║╚╗╚╝╚╗╔═╝╔╝║╚╗╚╗╚╗║╔══╝╔╗║╚╗║╚╗║║╚═╗║║║╚═══╗............
      .╚═╗╔╝...╔╗╔═╗║╔╗║╔═╝║╔══╝║║║.║║║║║║╔╝╚══╗║╔╗║╔╗╔═══════╝╔╝╚╝.╚╗║║╚══╗╔═╝╚╗╔╝╔╝╔══╝╚═╗║╔╝╔╝╔╝╔╝║║╔═╗║║╚╗║╚╗║║║╔╗║║║║╔╗╔╗╚╗...........
      ...║║....║║╚╗╚╝║║║╚══╝╚╗╔╗║║╚═╝║║║║║╚╗╔╗╔╝╚╝║╚╝║╚═╗╔╗╔╗╔╗║.╔═══╝║╚╗╔═╝╚═╗╔╝║╔╝.╚══╗╔═╝╚╝.╚╗╚╗╚╗║╚╝.╚╝║╔╝║╔╝║║╚╝║║║║║║╚╝╚═╝...........
      ...╚╝...╔╝╚═╝╔═╝║║╔═╗╔═╝║║║║╔╗╔╝║║║║╔╝║║╚═╗.║╔╗╚═╗╚╝╚╝║║║╚╗╚╗╔═╗╚╗║║.╔╗.║╚╗║╚╗╔═══╝╚═════╗╚╗╚╗║╚══╗.╔╝╚╗║║╔╝╚╗.║║╚╝║╚════╗...........
      ........╚╗╔╗╔╝╔═╝╚╝╔╝╚═╗║╚╝║║╚╝╔╝║╚╝╚╗║║╔╗╚╗╚╝║╔═╝╔═══╝║║╔╝╔╝╚╗╚═╝║╚═╝╚╗╚╗║║╔╝╚═══╗╔╗╔╗╔╗╚╗╚╗║╚╗╔═╝╔╝╔╗║╚╝╚═╗║.║║╔═╝╔╗╔═╗╚╗..........
      .........╚╝╚╝.╚╗╔═╗╚╗..╚╝.╔╝║╔═╝╔╝╔══╝║║║╚╗╚═╗║╚═╗╚═══╗║║╚╗╚╗╔╝╔══╝╔═╗╔╝.║║║╚╗╔╗╔╗║║╚╝╚╝╚═╝.╚╝.║╚╗╔╝╔╝║╚═╗╔═╝╚╗╚╝╚╗╔╝╚╝.║╔╝..........
      .............╔═╝╚╗║╔╝.....╚╗║║╔╗╚╗║╔╗╔╝╚╝.╚╗╔╝║╔╗║╔═══╝║║╔╝.║║.╚╗╔╗║.║╚╗╔╝║║╔╝║╚╝╚╝╚═════╗╔════╝╔╝╚╗║╔╝╔═╝║╔╗╔╝...╚╝....╚╝...........
      .............╚═╗╔╝╚╝.......╚╝║║║╔╝║║║║...╔═╝╚╗║║╚╝╚╗╔╗╔╝║╚═╗║║╔═╝║║╚╗║╔╝║╔╝║║.╚══╗╔╗╔═╗╔═╝║╔═══╗║╔╗╚╝╚╗╚═╗║║║╚╗╔╗....................
      ..............╔╝║............╚╝║║.╚╝║╚╗..╚═╗╔╝║╚╗..╚╝║╚╗║╔═╝╚╝║╔╗║╚╗║║╚╗║║╔╝╚══╗╔╝║║║╔╝╚╗.╚╝╔══╝╚╝╚╗.╔╝╔═╝╚╝╚╗╚╝║....................
      ..............╚╗║..............╚╝...╚═╝..╔═╝╚╗╚═╝.╔══╝╔╝║╚═══╗╚╝║║╔╝║║╔╝║║║╔╗╔╗║╚═╝║║║╔╗╚══╗║╔═╗╔═╗╚╗╚╗╚═╗...╚═╗╚╗...................
      ...............╚╝........................╚╗╔╗║....╚══╗║╔╝╔═╗╔╝.╔╝║╚╗║║║╔╝║║║║║║╚══╗║║╚╝║╔╗╔╝╚╝.║╚╗║╔╝╔╝╔╗║.....║╔╝...................
      ..........................................╚╝╚╝.......╚╝║╔╝.╚╝..╚╗║╔╝║║║║╔╝╚╝║║║╔╗╔╝║║.╔╝║╚╝.╔══╝╔╝╚╝.╚╗║╚╝.....╚╝....................
      ......................................................╔╝╚╗......╚╝╚╗║╚╝║╚══╗╚╝╚╝║╚╗╚╝.╚╗╚╗..╚══╗║.╔╗╔═╝╚═══╗.........................
      ......................................................║╔╗║.........║║.╔╝╔╗╔╝....║╔╝....╚╗║.....║╚═╝║║╔╗╔══╗╚╗........................
      ......................................................╚╝╚╝.........╚╝.╚╗║║║.....╚╝......╚╝.....║╔═╗║╚╝║╚╗.╚═╝........................
      .......................................................................╚╝║║...................╔╝╚╗╚╝..║╔╝............................
      .........................................................................╚╝...................╚═╗║....╚╝.............................
      ..............................................................................................╔═╝╚╗..................................
      ..............................................................................................╚═══╝..................................
      
  • # Un grand classique, mais toujour aussi long à résoudre

    Posté par  . Évalué à 2. Dernière modification le 10 décembre 2023 à 14:41.

    Quand j'ai vu que l'énoncé nous demandait de définir une boucle fermée, j'ai tout de suite senti qu'on allait devoir en calculer l'aire dans la partie suivante.
    Je ne me suis pas trompé.
    Dans la partie une, une récursion sur toute la boucle suffit (en augmentant la limite de récursion).
    Ma logique pour la partie deux est que certains motifs nous font entrer ou sortir de la boucle, il suffit de les repérer en parcourant toute la carte.
    Et beaucoup de gestion d'erreur pour repérer les erreurs de logique quand on code ou pour ne pas avoir à tester les longueurs des chaînes.
    Voici mon code :

    #!/bin/python3
    import sys
    
    sys.setrecursionlimit(10000)
    
    def getStart(puzzle):
        for i,l in enumerate(puzzle):
            for j,p in enumerate(l):
                if p == "S":
                    return [i,j]
    
    def initLoop(puzzle,countpipes=True,get_connections=False):
        start = getStart(puzzle)
        direction = ""
        connections = ""
        go_away = [0,0]
        try:
            if puzzle[start[0]-1][start[1]] in ["F","7","|"]:
                direction = "H"
                connections += direction
                go_away = [-1,0]
    
        except IndexError:
            pass
        try:
            if puzzle[start[0]][start[1]-1] in ["F","L","-"]:
                direction = "G"
                connections += direction
                go_away = [0,-1]
        except IndexError:
            pass
        try:
            if puzzle[start[0]][start[1]+1] in ["J","7","-"]:
                direction = "D"
                connections += direction
                go_away = [0,1]
        except IndexError:
            pass
        try:
            if puzzle[start[0]+1][start[1]] in ["J","L","|"]:
                direction = "B"
                connections += direction
                go_away = [1,0]
        except IndexError:
            pass
        start = [start[0]+go_away[0],start[1]+go_away[1]]
        if get_connections:
            return connections
        if countpipes:
            pipes.append(start)
        return round((browseLoop(puzzle, start, direction,countpipes)+1)/2)
    
    def browseLoop(puzzle, start, direction, countpipes=True):
        here = puzzle[start[0]][start[1]]
        if here == "-":
            if direction == "D":
                start = [start[0],start[1]+1]
            elif direction == "G":
                start = [start[0],start[1]-1]
            else:
                raise ValueError
        elif here == "|":
            if direction == "H":
                start = [start[0]-1,start[1]]
            elif direction == "B":
                start = [start[0]+1,start[1]]
            else:
                raise ValueError
        elif here == "L":
            if direction == "B":
                start = [start[0],start[1]+1]
                direction = "D"
            elif direction == "G":
                start = [start[0]-1,start[1]]
                direction = "H"
            else:
                raise ValueError
        elif here == "F":
            if direction == "H":
                start = [start[0],start[1]+1]
                direction = "D"
            elif direction == "G":
                start = [start[0]+1,start[1]]
                direction = "B"
            else:
                raise ValueError
        elif here == "7":
            if direction == "D":
                start = [start[0]+1,start[1]]
                direction = "B"
            elif direction == "H":
                start = [start[0],start[1]-1]
                direction = "G"
            else:
                raise ValueError
        elif here == "J":
            if direction == "D":
                start = [start[0]-1,start[1]]
                direction = "H"
            elif direction == "B":
                start = [start[0],start[1]-1]
                direction = "G"
            else:
                raise ValueError
        else:
            raise ValueError
        if countpipes:
            pipes.append(start)
        if puzzle[start[0]][start[1]] == "S":
            return 1
        else:
            return browseLoop(puzzle,start,direction)+1
    
    def areConnected(somepipes):
        if somepipes[0] not in ["F","L"]:
            return False
        if not all([i=="-" for i in somepipes[1:-1]]):
            return False
        if somepipes[-1] not in ["7","J"]:
            return False
        if somepipes[0] == "F" and somepipes[-1] == "J":
            return True
        if somepipes[0] == "L" and somepipes[-1] == "7":
            return True
        return False
    
    def floodPipes(puzzle):
        initLoop(puzzle,countpipes=True)
        connections = initLoop(puzzle,get_connections=True)
        start = getStart(puzzle)
        restart = ""
        if all([c in "HB" for c in connections]):
            restart = "|"
        elif all([c in "GD" for c in connections]):
            restart = "-"
        elif all([c in "HD" for c in connections]):
            restart = "L"
        elif all([c in "BD" for c in connections]):
            restart = "F"
        elif all([c in "HG" for c in connections]):
            restart = "J"
        elif all([c in "BG" for c in connections]):
            restart = "7"
        else:
            print(connections)
            raise ValueError
    
        puzzle[start[0]] = puzzle[start[0]].replace("S",restart)
        inloop = False
        surface = 0
        for i, l in enumerate(puzzle):
            inloop == False
            for j, p in enumerate(l):
                if [i,j] in pipes:
                    if puzzle[i][j] == "|":
                        inloop = not inloop
                    elif puzzle[i][j] in ["J","7"]:
                        r = puzzle[i][j]
                        iterator = j
                        try:
                            while puzzle[i][iterator] not in ["F","L"]:
                                iterator -= 1
                                r = puzzle[i][iterator] + r
                        except IndexError:
                            pass
                        if areConnected(r):
                            inloop = not inloop
    
                elif inloop:
                    surface += 1
    
        return surface
    
    def solve1(puzzle,testing=False):
        s=0
        s = initLoop(puzzle)
        if testing:
            print(s)
        return s
    
    def solve2(puzzle,testing=False):
        global pipes
        pipes = []
        s = 0
        s = floodPipes(puzzle)
        if testing:
            print(s)
        return s

    Il y a 10 sortes de gens dans le monde – ceux qui comprennent le ternaire, ceux qui ne le comprennent pas et ceux qui le confondent avec le binaire.

    • [^] # Re: Un grand classique, mais toujour aussi long à résoudre

      Posté par  . Évalué à 1.

      J'avais aussi commencé par une fonction récursive, mais elle ne dépassait la limite de recursion, je l'ai remplacé par une simple boucle while.

      inputs = open(f'input_d10.txt').read()
      
      grid=[]
      for y,l in enumerate(inputs.strip().split('\n')):
          if 'S' in l:
              start = l.find('S'), y
          grid.append([*l])
      
      H,W = len(grid)-1, len(grid[0])-1
      
      pipes = {
          '|': ((0,1),(0,-1)), 
          '-': ((1,0),(-1,0)),
          'L': ((0,-1),(1,0)),
          'J': ((0,-1),(-1,0)),
          '7': ((-1,0),(0,1)),
          'F': ((1,0),(0,1)),
          '.': ((0,0),(0,0))
      }
      
      dirs = {s:{i:o, o:i} for s,(i,o) in pipes.items()}
      
      
      def loop(dx,dy,x,y):
          l, path = 0, []
          while 1:
              if l and (x,y) == start:
                  return l, path
              path.append((x,y))
              nx, ny = x+dx, y+dy
              if nx<0>ny or nx>W or ny>H:
                  return None
              d = [(ndx,ndy) for dxy in map(dirs.get,grid[ny][nx]) 
                   for (ndx,ndy) in dxy if (nx+ndx,ny+ndy)==(x,y)]
              if not d:
                  return None
              ndx, ndy = dirs[grid[ny][nx]][d[0]]
              dx, dy, x, y, l = ndx, ndy, nx, ny, l+1
      
      
      ll, path = 0, []
      s = ''
      for p in pipes:
          x,y = start
          dx, dy = pipes[p][0]
          grid[y][x] = p
          if lp:=loop(dx,dy,x,y):
              if lp[0]>ll:
                  ll, path = lp
                  s = p
      
      part_1 = ll // 2
      print(f"{part_1=}")
      
      
      part_2 = 0
      x,y = path[0]
      grid[y][x] = s     
      path = set(path)
      prev_l = '.' * (W+1)
      
      for y,l in enumerate(grid):
          inside = 0
          for x,c in enumerate(l):
              if ((x,y) in path and (c=='|'  or 
                  (c in 'JL' and prev_l[x] in '|7F'))):
                  inside ^= 1
              elif (x,y) not in path:
                  part_2 += inside
          prev_l = l
      
      print(f"{part_2=}")
  • # Une solution assez élégante, je trouve.

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

    Attention, spoiler pour ceux qui luttent sur la partie 2 !

    Partie 1

    Pour la première c'est pas très difficile, on parcours le bidule.
    J'ai très mal dormi, je me suis pris la tête à partir dans les deux directions à la fois et à trouver le moment de la rencontre, alors qu'il suffit de parcourir une seule boucle et de diviser la longueur par deux, voici un algorithme assez efficace, même si probablement trop modélisé.
    Au passage, j'ai aplati la carte pour qu'elle soit en 1 dimension, c'est plus facile, mais pas autant pour la partie 2 :

    data = stdin.read()).strip().splitlines()
    LARGEUR = len(data[0])
    HAUTEUR = len(data)
    data = "".join(data)
    
    class Dir(IntEnum):
      X = 0
      N = -LARGEUR
      S = LARGEUR
      E = 1
      O = -1
    
    def tuile(N=Dir.X, S=Dir.X, E=Dir.X, O=Dir.X, sides=None):
      return {Dir.N: N, Dir.S: S, Dir.E: E, Dir.O: O}
    
    # changement de direction en fonction de la direction d'entrée dans une portion de tuyau
    vers_tuile = {
      ".": tuile(),
      "S": tuile(N=Dir.N, S=Dir.S, E=Dir.E, O=Dir.O),
      "|": tuile(N=Dir.N, S=Dir.S),
      "-": tuile(E=Dir.E, O=Dir.O),
      "L": tuile(S=Dir.E, O=Dir.N),
      "J": tuile(S=Dir.O, E=Dir.N),
      "7": tuile(N=Dir.O, E=Dir.S),
      "F": tuile(N=Dir.E, O=Dir.S),
    }
    Carte = [vers_tuile[_] for _ in data]
    start = data.index("S")
    explored = {start}
    explorer, direction = list(
      (start + direction, direction)
      for direction in Dir
      if direction and Carte[start + direction][direction]
    )[0]
    while True:
      explored.add(explorer)
      direction = Carte[explorer][direction]
      explorer = explorer + direction
      if explorer == start:
        break
    ex1 = len(explored) // 2

    Pour la suite, j'ai dû voir les choses et donc représenter mon bidule plus visuellement, on remplace |-LJ7F par │─└┘┐┌. J'ai totalement triché en remplaçant S par son symbole, après avoir observé les données, mais c'est pas si difficile de déterminer ça, et le rendu sur les données de test.

    data = "".join([
      _ if p in explored else "  "
      for p, _ in enumerate(data.translate(str.maketrans("|-LJ7F", "│─└┘┐┌")))
    ])
    for i in range(HAUTEUR):
      print(data[i * LARGEUR:(i + 1) * LARGEUR])
    
     ┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌───┐
     │└┘││││││││││││┌──┘
     └─┐└┘└┘││││││└┘└─┐ 
    ┌──┘┌──┐││└┘└┘ ┌┐┌┘ 
    └───┘┌─┘└┘    ┌┘└┘  
       ┌─┘┌───┐   └┐    
      ┌┘┌┐└┐┌─┘┌┐  └───┐
      └─┘└┐││┌┐│└┐┌─┐┌┐│
         ┌┘│││││┌┘└┐││└┘
         └─┘└┘└┘└──┘└┘  
    
      ┌┐ 
     ┌┘│ 
    ┌┘ └┐
    │┌──┘
    └┘

    Partie 2, et maintenant pour le spoiler !

    J'ai doublé la carte et reconstruit les tuyaux manquants. Ensuite il suffit d'explorer la zone vide à l'extérieur, on peut se faufiler partout vu qu'on a créé de l'espace entre les tuyaux.
    On transforme une case en quatre cases, on garde celle d'origine, et on étend logiquement à droite et en dessous, la 4è en bas à droite étant forcément vide.
    Les cartes d'exemple doublées donnent ça :

    : ┌─, : ., :└─, :., :., :──
       .     .    ..    ..    .    ..
    
    ..┌─┐.┌─┐.┌─┐.┌─┐.┌─┐.┌─┐.┌─┐.┌───────┐.
    ..│█│.│█│.│█│.│█│.│█│.│█│.│█│.│███████│.
    ..│█└─┘█│.│█│.│█│.│█│.│█│.│█│.│█┌─────┘.
    ..│█████│.│█│.│█│.│█│.│█│.│█│.│█│.......
    ..└───┐█└─┘█└─┘█│.│█│.│█│.│█└─┘█└───┐...
    ......│█████████│.│█│.│█│.│█████████│...
    ┌─────┘█┌─────┐█│.│█└─┘█└─┘███┌─┐█┌─┘...
    │███████│.....│█│.│███████████│.│█│.....
    └───────┘.┌───┘█└─┘█████████┌─┘.└─┘.....
    ..........│█████████████████│...........
    ......┌───┘█┌───────┐███████└─┐.........
    ......│█████│.......│█████████│.........
    ....┌─┘█┌─┐█└─┐.┌───┘█┌─┐█████└───────┐.
    ....│███│.│███│.│█████│.│█████████████│.
    ....└───┘.└─┐█│.│█┌─┐█│.└─┐█┌───┐█┌─┐█│.
    ............│█│.│█│.│█│...│█│...│█│.│█│.
    ..........┌─┘█│.│█│.│█│.┌─┘█└─┐.│█│.└─┘.
    ..........│███│.│█│.│█│.│█████│.│█│.....
    ..........└───┘.└─┘.└─┘.└─────┘.└─┘.....
    ........................................
    
    ....┌─┐...
    ....│█│...
    ..┌─┘█│...
    ..│███│...
    ┌─┘███└─┐.
    │███████│.
    │█┌─────┘.
    │█│.......
    └─┘.......
    ..........

    On « recompresse » ensuite en prenant les cases dont les coordonnées sont paires : (0, 0), (0, 2), (2, 2) etc.

    .┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌───┐
    .│└┘││││││││││││┌──┘
    .└─┐└┘└┘││││││└┘└─┐.
    ┌──┘┌──┐││└┘└┘█┌┐┌┘.
    └───┘┌─┘└┘████┌┘└┘..
    ...┌─┘┌───┐███└┐....
    ..┌┘┌┐└┐┌─┘┌┐██└───┐
    ..└─┘└┐││┌┐│└┐┌─┐┌┐│
    .....┌┘│││││┌┘└┐││└┘
    .....└─┘└┘└┘└──┘└┘..
    
    ..┌┐.
    .┌┘│.
    ┌┘█└┐
    │┌──┘
    └┘...

    Le reste c'est un décompte et hop, fini.
    Le code est plutôt moche, je le posterai plus tard quand je l'aurai rendu plus lisible.

    • Yth.
  • # Première partie

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

    C'est pour moi l'occasion d'utiliser enum.Flag qui correspond très bien à des trucs qui peuvent avoir une superposition d'états, ici des tuyaux connectés dans différentes directions.

    from collections.abc import Iterable, Sequence
    from typing import Optional, Self
    
    import enum
    import io
    
    import numpy as np
    import numpy.typing as npt
    
    import aoc
    
    
    Coords = tuple[int, int]
    
    
    class Tile(enum.Flag):
        NORTH = enum.auto()
        SOUTH = enum.auto()
        EAST = enum.auto()
        WEST = enum.auto()
    
        def __str__(self) -> str:
            if self is self.__class__(0):
                return ' '
            # if self is self.EAST:
            #     return '╶'
            # if self is self.WEST:
            #     return '╴'
            if self.NORTH in self:  # type: ignore
                if self.EAST in self:  # type: ignore
                    return '╚'
                if self.WEST in self:  # type: ignore
                    return '╝'
                if self.SOUTH in self:  # type: ignore
                    return '║'
                # if self is self.NORTH:
                #     return '╵'
            if self.SOUTH in self:  # type: ignore
                if self.EAST in self:  # type: ignore
                    return '╔'
                if self.WEST in self:  # type: ignore
                    return '╗'
                # if self is self.SOUTH:
                #     return '╷'
            if self.EAST in self:  # type: ignore
                if self.WEST in self:  # type: ignore
                    return '═'
            # if self is self.WEST:
            #     return '╴'
            raise ValueError('unexpected value %s' % repr(self))
    
        def vector(self) -> Coords:
            if self is self.NORTH:
                return (-1, 0)
            if self is self.SOUTH:
                return (1, 0)
            if self is self.EAST:
                return (0, 1)
            if self is self.WEST:
                return (0, -1)
            raise ValueError('cannot convert multiple directions to vector')
    
        @classmethod
        def import_char(cls, char: str) -> Self:
            if char == '.' or char == ' ':
                return cls(0)
            if char == '|':
                return cls.NORTH | cls.SOUTH  # type: ignore
            if char == '-':
                return cls.EAST | cls.WEST  # type: ignore
            if char == 'L':
                return cls.NORTH | cls.EAST  # type: ignore
            if char == 'J':
                return cls.NORTH | cls.WEST  # type: ignore
            if char == '7':
                return cls.SOUTH | cls.WEST  # type: ignore
            if char == 'F':
                return cls.SOUTH | cls.EAST  # type: ignore
            raise ValueError('unsupported pipe description %s' % char)

    Et la carte maintenant :

    class Map:
        def __init__(self, array: Sequence[Sequence[Tile]], start: Coords):
            self.matrix: npt.NDArray[np.object_] = np.array(array)
            self.ly, self.lx = self.matrix.shape
            self.start = start
    
        @classmethod
        def import_lines(cls, lines: Iterable[str]) -> Self:
            start: Optional[Coords] = None
    
            array: list[list[Tile]] = []
            for y, line in enumerate(lines):
                array.append([])
                for x, char in enumerate(line.rstrip()):
                    if char == 'S':
                        start = (y, x)
                        array[-1].append(Tile(0))
                    else:
                        array[-1].append(Tile.import_char(char))
    
            map_ = cls(array, (0, 0))
            if start is not None:
                y, x = start
                connections = Tile(0)
                if y >= 1 and Tile.SOUTH in map_[y - 1, x]:
                    connections |= Tile.NORTH
                if y < map_.ly - 1 and Tile.NORTH in map_[y + 1, x]:
                    connections |= Tile.SOUTH
                if x >= 1 and Tile.EAST in map_[y, x - 1]:
                    connections |= Tile.WEST
                if x < map_.lx - 1 and Tile.WEST in map_[y, x + 1]:
                    connections |= Tile.EAST
                map_[y, x] = connections
                map_.start = start
                return map_
            else:
                raise ValueError('start position not found')
    
        def neighs(self, coords: Coords) -> Iterable[Coords]:
            y, x = coords
            for direction in self[coords]:
                dy, dx = direction.vector()
                y_, x_ = y + dy, x + dx
                if y_ >= 0 and y_ < self.ly and x_ >= 0 and x_ < self.lx:
                    yield y_, x_
    
        def __getitem__(self, coords: Coords) -> Tile:
            return self.matrix[coords]
    
        def __setitem__(self, coords: Coords, value: Tile):
            self.matrix[coords] = value
    
        def __str__(self):
            s = io.StringIO()
            for line in self.matrix:
                for tile in line:
                    s.write(str(tile))
                s.write('\n')
            return s.getvalue()
    
        def farthest(self) -> int:
            distances: npt.NDArray[np.int_] = np.full(self.matrix.shape, -1, dtype=np.int_)
            distance = 0
            currents: set[Coords] = {self.start}
            while len(currents) > 0:
                nexts: set[Coords] = set()
                for current in currents:
                    if distances[current] >= 0:
                        continue
                    distances[current] = distance
                    nexts.update(self.neighs(current))
                currents = nexts
                distance += 1
            return distances.max()

    La solution est donnée par la méthode Map.farthest(). C'est un parcours itératif de proche en proche :

    1. on construit une matrice de distances au point de départ, initialisée avec des -1 partout ;
    2. on commence avec une distance courante de zéro et le point de départ comme unique point courant, mais plus tard on en aura plusieurs (en pratique, deux, mais ça pourrait être plus si on avait des tuyaux trifides) ;
    3. pour chaque point courant si aucune distance n'a été précédemment relevée, on note la distance courante et on place ses voisins reliés dans l'ensemble des prochains points courants ;
    4. on continue, et on ne s'arrête que quand il n'y a plus aucun point courant.
    • [^] # Re: Première partie

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

      Et pour la deuxième partie, résolue grâce à l'idée de Pierre :

      class Map:
          def simplify(self) -> None:
              connecteds: npt.NDArray[np.bool_] = np.zeros(self.matrix.shape, dtype=np.bool_)
              currents: set[Coords] = {self.start}
              while len(currents) > 0:
                  nexts: set[Coords] = set()
                  for current in currents:
                      if connecteds[current]:
                          continue
                      connecteds[current] = True
                      nexts.update(self.neighs(current))
                  currents = nexts
              for index, connected in np.ndenumerate(connecteds):
                  if not connected:
                      self.matrix[index] = Tile(0)
      
          def area(self) -> int:
              total = 0
              for line in self.matrix:
                  inside: bool = False
                  for tile in line:
                      if inside and tile is Tile(0):
                          total += 1
                      if Tile.NORTH in tile:
                          inside = not inside
              return total

      Première étape, simplifier la carte en virant tous les tuyaux inutiles. Comme pour la première partie, c'est basé sur un parcours de proche en proche pour identifier les tuyaux connectés au point de départ. Ensuite, on parcours tout, puis on met à zéro les tuiles qui contenaient des tuyaux non connectés.

      En fait, on parcours chaque ligne en gardant en mémoire si on est à l'intérieur de la boucle de tuyaux ou non. Seulement, à l'intérieur ou à l'extérieur, c'est ambigu lorsqu'on est justement sur un tuyau qui fait partie du réseau. Donc, pour être plus précis, on s'intéresse au fait que la zone en haut à gauche de chaque tuile est à l'intérieur ou non. Et vous pouvez faire tous les schémas que vous voulez, la seule chose qui fait changer l'état intérieur/extérieur de la zone en haut à gauche de la tuile suivante, c'est la présente d'un tuyau connecté au nord.

      Quant à l'aire, les tuiles qui y contribuent sont celles qui sont à l'intérieur et qui sont vides (après élimination de tuyaux inutiles). Voilà !

      • [^] # Re: Première partie

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

        T'aime bien faire plus générique que l'énoncé, parce qu'on sait sans regarder les données que les tuyaux sont à deux entrées, jamais de bifurcations, alors joli travail hyper générique, et proprement modélisé :)
        J'aime bien les enum.Flags, ça peut être vraiment utile.
        J'ai conçu une super machine à états avec un enum.Flags dans mon projet professionnel actuel, c'est tout propre et tout le monde comprend le code !

        Et je constate aussi que je suis finalement le seul bourrin à avoir zoomé sur la carte pour la voir plus en détail, c'est bien propre comme résolution de la partie 2. Et plus rapide que ma solution aussi, mais que je n'ai pas optimisée du tout (du tout (elle prend toute une longue seconde à s'exécuter !!)).

        • Yth.
  • # Solution en Haskell

    Posté par  . Évalué à 1. Dernière modification le 11 décembre 2023 à 17:29.

    Voici ma solution en Haskell.
    La partie 1 utilise un BFS mais c'est un peu overkill.
    La partie 2 repose sur des idées similaires à ce qu'a proposé Pierre.
    Une partie non négligeable du code (la fonction getNiceInput) chercher à determiner quelle est la tuile adéquate pour remplacer la tuile Start.

    import           AOC.Prelude hiding (head)
    import           Data.List (head, maximum)
    import qualified Data.HashMap.Strict as Map
    import qualified Data.HashSet as Set
    import           AOC (aoc)
    import           AOC.Parser (Parser, choice, eol, sepEndBy1, some)
    import           AOC.Search (bfs)
    import           AOC.Util (adjacentPoints, listTo2dMap)
    import           AOC.Tuple (thd3)
    
    data Tile = NS | EW | NE | NW | SW | SE | Empty | Start deriving (Eq)
    type Coord = (Int, Int)
    type Input = [[Tile]]
    type Matrix = HashMap Coord Tile
    
    parser :: Parser Input
    parser =  some tile `sepEndBy1` eol where
        tile = choice [NS <$ "|", EW <$ "-", NE <$"L", NW <$ "J", SW <$ "7", SE <$ "F", Empty <$ ".", Start <$ "S"]
    
    -- returns the start coordinate and the input where the start tile is replaced with the adequate tile 
    getNiceInput :: Input -> (Input, Matrix, Coord)
    getNiceInput tiles = (cleanedTiles, cleanedMat, start) where
        start = head [pos | (pos, Start) <- Map.toList mat]
        mat = listTo2dMap tiles
        adequateTile = case [start `elem` neighbors mat nbor | nbor <- neighbors mat start] of
            -- (x-1, y), (x+1, y), (x, y-1), (x, y+1)
            [True, True, False, False] -> NS
            [False, False, True, True] -> EW
            [True, False, False, True] -> NE
            [True, False, True, False] -> NW
            [False, True, False, True] -> SE
            [False, True, True, False] -> SW
            _ -> Empty  -- cannot happen if the input is nice
        cleanedMat = Map.insert start adequateTile mat
        cleanedTiles = [ [ if tile == Start then adequateTile else tile | tile <- row] 
                       | row <- tiles
                       ]
    
    neighbors :: Matrix -> Coord -> [Coord]
    neighbors mat (i, j) = case mat Map.!? (i, j) of
        Just NS -> [(i-1, j), (i+1, j)]
        Just EW -> [(i, j-1), (i, j+1)]
        Just NE -> [(i-1, j), (i, j+1)]
        Just NW -> [(i, j-1), (i-1, j)]
        Just SW -> [(i+1, j), (i, j-1)]
        Just SE -> [(i, j+1), (i+1, j)]
        Just Start -> adjacentPoints (i, j)
        _ -> []
    
    part1 :: Input -> Int
    part1 tiles = maximum . map fst $ bfs (neighbors mat) start where 
        (_, mat, start) = getNiceInput tiles
    
    part2 :: Input -> Int
    part2 tiles = sum . map countRow $ cleanedTiles where
        (tiles', mat, start) = getNiceInput tiles
        loopSet = Set.fromList . map snd $ bfs (neighbors mat) start
        -- replace each tile not in the loop with an empty tile
        cleanedTiles = [ [ if (i, j) `Set.member` loopSet then tile else Empty
                         | (j, tile) <- zip [0..] row
                         ] 
                       | (i, row) <- zip [0..] tiles'
                       ]
        countRow = thd3 . foldl' go (False, False, 0)
        go (isInside, fromNorth, counter) = \case
            NS -> (not isInside, fromNorth, counter)
            NE -> (isInside, True, counter)
            SE -> (isInside, False, counter)
            NW -> (isInside == fromNorth, fromNorth, counter)
            SW -> (isInside /= fromNorth, fromNorth, counter)
            Empty -> (isInside, fromNorth, if isInside then counter+1 else counter)
            _ -> (isInside, fromNorth, counter)
    
    solve :: Text -> IO ()
    solve = aoc parser part1 part2
  • # Ma solution

    Posté par  . Évalué à 1.

    Pour la deuxième partie, j'ai opté pour une solution où je remplace les tuiles de base par des tuiles de 3x3
    Je remplie ensuite en faisant les cellules en bordure de la map.

    Note: Ce code doit être utilisée --Xms2G pour avoir une stack plus grande que celle par défaut.

    package aoc;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.Stack;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    
    import aoc.Aoc2023s10p1.Direction;
    import aoc.Aoc2023s10p1.Maze;
    import aoc.Aoc2023s10p1.Pipe;
    
    public class Aoc2023s10p2 {
        public enum Direction {
            N(0, -1), S(0, 1), E(1, 0), W(-1, 0);
    
            int dx;
            int dy;
    
            Direction(int dx, int dy) {
                this.dx = dx;
                this.dy = dy;
            }
    
            Direction comeFrom() {
                if (this == N) {
                    return S;
                } else if (this == E) {
                    return W;
                } else if (this == W) {
                    return E;
                } else if (this == S) {
                    return N;
                }
                throw new RuntimeException();
            }
        }
        public enum Pipe {
    
            V('|', Arrays.asList(Direction.N, Direction.S),
                    new int[][] {new int[]{0, 1, 0}, new int[]{0, 1, 0}, new int[]{0, 1, 0}}
                    ), // is a vertical pipe connecting north and south.
            H('-', Arrays.asList(Direction.E, Direction.W),
                    new int[][] {new int[]{0, 0, 0}, new int[]{1, 1, 1}, new int[]{0, 0, 0}}
                    ), // is a horizontal pipe connecting east and west.
            L('L', Arrays.asList(Direction.N, Direction.E),
                    new int[][] {new int[]{0, 1, 0}, new int[]{0, 1, 1}, new int[]{0, 0, 0}}
                    ), // , is a 90-degree bend connecting north and east.
            J('J', Arrays.asList(Direction.N, Direction.W),
                    new int[][] {new int[]{0, 1, 0}, new int[]{1, 1, 0}, new int[]{0, 0, 0}}
                    ), // is a 90-degree bend connecting north and west.
            _7('7', Arrays.asList(Direction.S, Direction.W),
                    new int[][] {new int[]{0, 0, 0}, new int[]{1, 1, 0}, new int[]{0, 1, 0}}
                    ), // is a 90-degree bend connecting south and west.
            F('F', Arrays.asList(Direction.S, Direction.E),
                    new int[][] {new int[]{0, 0, 0}, new int[]{0, 1, 1}, new int[]{0, 1, 0}}
                    ), // is a 90-degree bend connecting south and east.
            D('.', Collections.emptyList(),
                    new int[][] {new int[]{0, 0, 0}, new int[]{0, 0, 0}, new int[]{0, 0, 0}}
                    ), // is ground; there is no pipe in this tile.
            S('S', Arrays.asList(Direction.N, Direction.S, Direction.E, Direction.W),
                    new int[][] {new int[]{0, 1, 0}, new int[]{1, 1, 1}, new int[]{0, 1, 0}}
                    ),// is the starting position of the
                                                                                        // animal; there is a pipe on this
                                                                                        // tile, but your sketch doesn't
                                                                                        // show what shape the pipe has.
            ;
    
            char c;
            List<Direction> directions;
            int[][] matrix;
    
            Pipe(char c, List<Direction> directions, int[][] matrix) {
                this.c = c;
                this.directions = directions;
                this.matrix = matrix;
            }
    
            boolean acceptFrom(Direction d) {
                return directions.contains(d);
            }
        }
        public static class Maze2 {
            List<List<Pipe>> maze;
            final int heightMap;
            final int widthMap;
            final int[][] map;
            final int[][] weights;
    
            final int[][] externs;
    
            Maze2(List<List<Pipe>> maze) {
                this.maze = maze;
    
                int height = maze.size();
                int width = maze.get(0).size();     
                weights = new int[height][width];
                computeWeight();
    
                heightMap = height*3;
                widthMap = width*3;
                map = new int[heightMap][widthMap];
                externs = new int[heightMap][widthMap];
                for (int x = 0; x < width; x++) {
                    for (int y = 0; y < height; y++) {
    
                        if(weights[y][x] != Integer.MAX_VALUE) {
                            writeMatrix(maze, x, y);
                        }
                    }
                }
    
                for (int x = 0; x < widthMap; x++) {
                    for (int y = 0; y < heightMap; y++) {
                        externs[y][x] = -1;
                        if (map[y][x] == 1) {
                            externs[y][x] = 0;
                        }
    
                    }
                }
    
                for (int x = 0; x < widthMap; x++) {
                    fillEnclosed(x, 0);
                    fillEnclosed(x, heightMap - 1);
                }
    
                for (int y = 0; y < heightMap; y++) {
                    fillEnclosed(0, y);
                    fillEnclosed(widthMap - 1, y);
                }
    
            }
    
            private void writeMatrix(List<List<Pipe>> maze, int x, int y) {
                Pipe p = maze.get(y).get(x);
                for (int dy = 0; dy < 3; dy++) {
                    for (int dx = 0; dx < 3; dx++) {
                        int m = p.matrix[dy][dx];
                        map[y*3 +dy][x*3 + dx] = m;
                    }
                }
            }
    
            private void fillEnclosed(int x, int y) {
                if (x < 0 
                        || x >= widthMap 
                        || y < 0 
                        || y >= heightMap) {
                    return;
                }
                if (map[y][x] == 1) {
                    return;
                }
    
                if (externs[y][x] < 0) {
                    externs[y][x] = 1;
    
                    for (Direction d : Direction.values()) {
                        fillEnclosed(x + d.dx, y + d.dy);
                    }               
                }
            }
    
            public void print() {
                for(int y=0;y < heightMap;y++) {
                    for(int x=0;x < widthMap;x++) {
                        System.out.print(map[y][x]);
                    }
                    System.out.println();
                }
    
                for(int y=0;y < heightMap;y++) {
                    for(int x=0;x < widthMap;x++) {
                        int i = externs[y][x];
                        if(i < 0) {
                            System.out.print("I");
                        } else if(i == 0) {
                            System.out.print("#");
                        } else {
                            System.out.print(".");
                        }
    
                    }
                    System.out.println();
                }
            }
    
            public int countEnclosed() {
                int max = 0;
                int height = maze.size();
                int  width= maze.get(0).size(); 
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
    
                        if(emptyTile(x, y)) {
                            max++;
                        }       
                    }
                }
                return max;
            }
    
            public boolean emptyTile(int x, int y) {
                for (int dy = 0; dy < 3; dy++) {
                    for (int dx = 0; dx < 3; dx++) {
    
                        if(externs[y*3+dy][x*3+dx] >= 0) {
                            return false;
                        }
                    }
                }
                return true;
            }
    
            public void computeWeight() {
                int height = maze.size();
                int width = maze.get(0).size(); 
    
                int sx = 0;
                int sy = 0;
                for(int x=0;x < width;x++) {
                    for(int y=0;y < height;y++) {
                        weights[y][x] = Integer.MAX_VALUE;
                        if(maze.get(y).get(x) == Pipe.S) {
                            weights[y][x] = 0;
                            sx = x;
                            sy = y;
                        }
                    }
                }
    
                fillWeightFrom(sx, sy);
            }
    
            private void fillWeightFrom(int cx, int cy) {
                int w = weights[cy][cx];
                Pipe currentPipe = this.maze.get(cy).get(cx);
    
                for(Direction d : Direction.values()) {
    
                    if(currentPipe.directions.contains(d)) {
                        int dx = cx+ d.dx;
                        int dy = cy+ d.dy;
                        Pipe nextPipe = next(dx, dy);
                        if(nextPipe != null) {
                            if(nextPipe.acceptFrom(d.comeFrom())) {
                                int wn = weights[dy][dx];
                                if(wn > (w+1)) {
                                    weights[dy][dx] = w+1;
                                    fillWeightFrom(dx, dy);
                                }
                            }
                        }
                    }               
                }       
            }
    
            public Pipe next(int cx, int cy) {
                int height = maze.size();
                int width = maze.get(0).size(); 
                if(cx < 0 || cx >= width) {
                    return null;
                }
                if(cy < 0 || cy >= height) {
                    return null;
                }
    
                return this.maze.get(cy).get(cx);
            }
        }
        public static Map<String, Pipe> pipeBySymbol = Arrays.stream(Pipe.values())
                .collect(Collectors.toMap(p -> "" + p.c, p -> p));
        public static void main(String[] args) {
    
            try (Scanner in = new Scanner(Aoc2023s10p2.class.getResourceAsStream("res/Aoc2023s10p1.txt"))) {
                String row;
                List<List<Pipe>> maze = new ArrayList<>();
                while (in.hasNext()) {
                    row = in.nextLine();
    
                    maze.add(row.chars().mapToObj(i -> pipeBySymbol.get(String.valueOf((char) i))).toList());
    
                }
    
                Maze2 mazeSolve = new Maze2(maze);
                mazeSolve.print();
                System.out.println(mazeSolve.countEnclosed());
            }
        }
    
    }

Suivre le flux des commentaires

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