Advent of code

 23 décembre 2023 

  A Long Walk : Trouver parcours le plus long sans repasser par le même chemin
#.##################
   
#.#...#...#.........
   
#.#.#.#.#.#.#######.
   
#.#.#...#.#.......#.
   
#.#.#####.#######.#.
   
#.#.#.....#...#...#.
   
#.#.#.#####.#.#.###.
   
#.#.#...#...#.#...#.
   
#.#.###.#.###v###.##
   
#...###.#.###.>.#...
   
#######.#.###v#.###.
   
#.......#.#...#...#.
   
          
  1. code.py
  2. code1_lent.py
  3. soluceGraphe1.png
  4. soluceGraphe2.png
  5. grapheurCodePourri.py
import time, math
from random import random
from itertools import pairwise


auto = False



from tkinter import *
fen = Tk()

HEIGHT=900
WIDTH=1000
ZOOM = 3

canvas = Canvas(fen, bg='white', height=HEIGHT, width=WIDTH)
canvas.pack(side=TOP)

outline='black'
width=2
color='black'


def line(q1, q2):
    global canvas, width, color
    canvas.create_line(q1[0], q1[1], q2[0], q2[1], width=width, fill=color)

def texte(p, texte):
    global canvas
    canvas.create_text(p[0] - 20, p[1] - 10, anchor=W, font="Purisa", text=texte)

def cercle(centre, rayon):
    global canvas, width, color, outline
    q = centre
    canvas.create_oval(q[0] - rayon, q[1] - rayon, q[0] + rayon, q[1] + rayon, width=width, fill=color, outline=outline)

def effacerCanvas():
  global canvas
  canvas.delete(ALL)

verts = set()
#for i,j in pairwise( [0, 4, 12, 16, 23, 25,37,33, 34, 26, 29, 22, 20, 15, 7, 11, 2, 3, 6, 8, 13, 24, 19, 14, 9, 5,36,10, 17, 21, 28, 30, 27, 31, 35, 32, 1]):
for i,j in pairwise( [0,4,12,16,23,25,37,33,34,26,20,22,18,15,7,11,2,3,6,8,13,24,19,14,9,5,36,10,17,21,28,30,27,31,35,32,1] ):
    verts.update([(i,j), (j,i)])
fixes = {0:(60,160), 1:(300,160)}

base = {
0:[(101, 4)],
1:[(147, 32)],
2:[(174, 11), (194, 3), (100, 4)],
3:[(152, 7), (172, 6), (194, 2)],
4:[(280, 12), (101, 0), (100, 2)],
5:[(164, 9), (264, 36), (102, 6)],
6:[(108, 8), (102, 5), (172, 3)],
7:[(180, 15), (152, 3), (48, 8), (232, 11)],
8:[(154, 13), (108, 6), (166, 9), (48, 7)],
9:[(112, 14), (164, 5), (112, 10), (166, 8)],
10:[(240, 17), (264, 36), (112, 9)],
11:[(172, 18), (174, 2), (232, 7), (62, 12)],
12:[(184, 16), (280, 4), (62, 11)],
13:[(194, 24), (154, 8), (104, 14), (138, 15)],
14:[(78, 19), (112, 9), (88, 17), (104, 13)],
15:[(168, 20), (180, 7), (138, 13), (156, 18)],
16:[(230, 23), (184, 12), (114, 18)],
17:[(206, 21), (240, 10), (88, 14)],
18:[(110, 22), (172, 11), (156, 15), (114, 16)],
19:[(140, 30), (78, 14), (60, 21), (320, 24)],
20:[(84, 26), (168, 15), (76, 24), (130, 22)],
21:[(116, 28), (206, 17), (60, 19)],
22:[(94, 29), (110, 18), (130, 20), (86, 23)],
23:[(194, 25), (230, 16), (86, 22)],
24:[(76, 27), (194, 13), (320, 19), (76, 20)],
25:[(201, 37), (194, 23), (182, 29)],
26:[(166, 34), (84, 20), (80, 27), (88, 29)],
27:[(130, 31), (76, 24), (136, 30), (80, 26)],
28:[(104, 32), (116, 21), (164, 30)],
29:[(204, 33), (94, 22), (88, 26), (182, 25)],
30:[(104, 35), (140, 19), (164, 28), (136, 27)],
31:[(130, 27), (298, 35), (72, 34)],
32:[(147, 1), (104, 28), (188, 35)],
33:[(204, 29), (266, 34), (201, 37)],
34:[(166, 26), (72, 31), (266, 33)],
35:[(104, 30), (188, 32), (298, 31)],
36:[(264,5), (264,10)],
37:[(201,25), (201,33)],
}


aretes = {}
distances = {}
for k, v in base.items():
    aretes[k] = [s for _,s in v]
    distances[k] = dict([(s,d) for d,s in v])

noms = list(aretes.keys())
aretes2 = []
points = []
k = 0
listeNoms = []
for nom in noms:
  k += 1
  voisins = aretes[nom]
  aretes2 += [ [ noms.index(voisins[i]) for i in range(len(voisins)) ] ]
  points += [ [ WIDTH / 2 / ZOOM + WIDTH/2.2 / ZOOM * math.cos(2*math.pi * k / len(noms)), HEIGHT / 2 / ZOOM + HEIGHT/2.2/ZOOM * math.sin(2*math.pi * k / len(noms)) ] ]
  if nom < 2:
     nomV = ('START', 'END')[nom]
  elif nom < 28:
    nomV = chr(ord('A') + nom - 2)
  else:
    nomV = chr(ord('a') + nom - 28)
  #listeNoms += [ nomV ]
  #listeNoms += [ nom ]
  listeNoms += [ '' ]
aretes = aretes2
points[0] = (10,10)

def zoom(p, x=None):
    if x is not None:
        p = [p, x]
    return [v*ZOOM for v in p]
def dessiner(points, aretes, listeNoms):
  global color
  effacerCanvas()
  for i in range(len(aretes)):
    a = aretes[i]
    for a2 in a:
      color = 'red'
      d = distances[i][a2]
      global width
      width = max(3, 2+int( (d-70) / 20 ))
      if (i,a2) in verts:
        color = 'green'
      else:
        color = 'red'
      line(zoom(points[i]), zoom(points[a2]))
      texte(zoom((points[i][0] + points[a2][0]) / 2, (points[i][1] + points[a2][1]) / 2), d)
  for i in range(len(points)):
    #for p in points:
    p = zoom(points[i])
    cercle(p, 5)
    texte(p, listeNoms[i]) 

dessiner(points, aretes, listeNoms)

def animer():
        global points, aretes, listeNoms, canvas, color, STOP
        if STOP:
            return

        bouge = True
        
        points2 = [ ]
        bouge = False
        for i in range(len(points)):
            if i in fixes:
                points2.append(fixes[i])
                continue
            dx = 0
            dy = 0
            px = points[i][0]
            py = points[i][1]
            for j in range(len(points)):
                if i == j:
                    continue
                dpx = (px - points[j][0])
                dpy = (py - points[j][1])
                d = dpx**2 + dpy**2 + 0.0000001
                #print("aretes:", aretes[i])
                if (j in aretes[i]):
                    f = min(50, max(0, (1*d - 150))) / 10
                    m = (dpx == 0 and 1 or (dpy * 1. / dpx))
                    fx = f * (dpx > 0 and 1 or -1 ) / math.sqrt(1+m*m)
                    #line((px, py), (px-fx, py-fx*m))
                    dx -= fx
                    dy -= m * fx

                f = min(5, max(0, (2000 - d)))
                m = (dpx == 0 and 1 or (dpy * 1. / dpx))
                fx = f * (dpx > 0 and 1 or -1 ) / math.sqrt(1+m*m)
                color='green'
                line((px, py), (px+fx, py+fx*m))
                dx += fx
                dy += m * fx


                
            if dx*dx + dy*dy > 2:
                bouge = True    
            #print(i, "bouge de", dx, dy, ". Bouge :", (bouge and 'oui' or 'non'))
            points2 += [ [ px + dx, py + dy] ]
        points = points2
        color='black'
        dessiner(points, aretes, listeNoms)
        if bouge:
            canvas.after(1, animer)



bou = Button(fen, text='Quitter', command=fen.destroy)
bou.pack(side=LEFT)

affichage = Label(fen, text='Couleur : ', fg='Black')
affichage.pack()

def clic(event):
  global points, clicPoint, auto

  if event.x > WIDTH - 100 and event.y > HEIGHT - 100:
        for i,p in enumerate(points):
            points[i] = grille(*p)
        dessiner(points, aretes, listeNoms)
        return

  if auto:
    animer()
    return

  clicPoint = trouverPoint(points, event.x, event.y)
  #if clicPoint == None:
  #  clicPoint = ajouterPoint(points, event.x, event.y)
    
def mouseDouble(event):
  global points, clicPoint, STOP
  if STOP:
    STOP = False
    animer()
  else:
    STOP = True
  #clicPoint = trouverPoint(points, event.x, event.y)
  #if clicPoint != None:
  #  points.pop(clicPoint)
  #  clicPoint = None
  #  rafraichir(points)
    

def dist(x1, y1, x2, y2):
    return math.sqrt((x1-x2)**2 + (y1-y2)**2)
def trouverPoint(points, x, y):
  for i in range(len(points)):
    if dist(points[i][0]*ZOOM, points[i][1]*ZOOM, x, y) < 8:
      return i
  return None

def grille(x,y):
    return [ round(v/20)*20 for v in (x,y)]
clicPoint = None
def mouseMoved(event):
    global points, aretes, listeNoms, clicPoint, auto
  
    if auto:
       return

    if clicPoint == None:
      return
    points[clicPoint] = grille(event.x/ZOOM, event.y/ZOOM)
    ### while (clicPoint > 1 and points[clicPoint][0] < points[clicPoint-1][0]):
    ###   (points[clicPoint], points[clicPoint - 1]) = (points[clicPoint - 1], points[clicPoint])
    ###   clicPoint -= 1
    ### while (clicPoint < len(points) - 1 and points[clicPoint][0] > points[clicPoint+1][0]):
    ###   (points[clicPoint], points[clicPoint + 1]) = (points[clicPoint + 1], points[clicPoint])
    ###   clicPoint += 1

    #rafraichir(points)
    dessiner(points, aretes, listeNoms)

def mouseReleased(event):
    global clicPoint
    clicPoint = None


canvas.bind("<Button-1>", clic)
canvas.bind("<Motion>", mouseMoved)
canvas.bind("<ButtonRelease-1>", mouseReleased)
canvas.bind("<Double-Button-1>", mouseDouble)

STOP = True

fen.mainloop()
if auto:
  animer()