Autor Tema: Advent of code, solución día 9

0 Usuarios y 1 Visitante están viendo este tema.

09 Diciembre, 2022, 06:02 pm
Leído 604 veces

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Hola a todos,

Aquí van los enunciados de hoy (Rope Bridge).
Parte 1:
Spoiler
This rope bridge creaks as you walk along it. You aren't sure how old it is, or whether it can even support your weight.

It seems to support the Elves just fine, though. The bridge spans a gorge which was carved out by the massive river far below you.

You step carefully; as you do, the ropes stretch and twist. You decide to distract yourself by modeling rope physics; maybe you can even figure out where not to step.

Consider a rope with a knot at each end; these knots mark the head and the tail of the rope. If the head moves far enough away from the tail, the tail is pulled toward the head.

Due to nebulous reasoning involving Planck lengths, you should be able to model the positions of the knots on a two-dimensional grid. Then, by following a hypothetical series of motions (your puzzle input) for the head, you can determine how the tail will move.

Due to the aforementioned Planck lengths, the rope must be quite short; in fact, the head (H) and tail (T) must always be touching (diagonally adjacent and even overlapping both count as touching):

....
.TH.
....

....
.H..
..T.
....

...
.H. (H covers T)
...

If the head is ever two steps directly up, down, left, or right from the tail, the tail must also move one step in that direction so it remains close enough:

.....    .....    .....
.TH.. -> .T.H. -> ..TH.
.....    .....    .....

...    ...    ...
.T.    .T.    ...
.H. -> ... -> .T.
...    .H.    .H.
...    ...    ...

Otherwise, if the head and tail aren't touching and aren't in the same row or column, the tail always moves one step diagonally to keep up:

.....    .....    .....
.....    ..H..    ..H..
..H.. -> ..... -> ..T..
.T...    .T...    .....
.....    .....    .....

.....    .....    .....
.....    .....    .....
..H.. -> ...H. -> ..TH.
.T...    .T...    .....
.....    .....    .....

You just need to work out where the tail goes as the head follows a series of motions. Assume the head and the tail both start at the same position, overlapping.

For example:

R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2

This series of motions moves the head right four steps, then up four steps, then left three steps, then down one step, and so on. After each step, you'll need to update the position of the tail if the step means the head is no longer adjacent to the tail. Visually, these motions occur as follows (s marks the starting position as a reference point):

== Initial State ==

......
......
......
......
H.....  (H covers T, s)

== R 4 ==

......
......
......
......
TH....  (T covers s)

......
......
......
......
sTH...

......
......
......
......
s.TH..

......
......
......
......
s..TH.

== U 4 ==

......
......
......
....H.
s..T..

......
......
....H.
....T.
s.....

......
....H.
....T.
......
s.....

....H.
....T.
......
......
s.....

== L 3 ==

...H..
....T.
......
......
s.....

..HT..
......
......
......
s.....

.HT...
......
......
......
s.....

== D 1 ==

..T...
.H....
......
......
s.....

== R 4 ==

..T...
..H...
......
......
s.....

..T...
...H..
......
......
s.....

......
...TH.
......
......
s.....

......
....TH
......
......
s.....

== D 1 ==

......
....T.
.....H
......
s.....

== L 5 ==

......
....T.
....H.
......
s.....

......
....T.
...H..
......
s.....

......
......
..HT..
......
s.....

......
......
.HT...
......
s.....

......
......
HT....
......
s.....

== R 2 ==

......
......
.H....  (H covers T)
......
s.....

......
......
.TH...
......
s.....

After simulating the rope, you can count up all of the positions the tail visited at least once. In this diagram, s again marks the starting position (which the tail also visited) and # marks other positions the tail visited:

..##..
...##.
.####.
....#.
s###..

So, there are 13 positions the tail visited at least once.

Simulate your complete hypothetical series of motions. How many positions does the tail of the rope visit at least once?
[cerrar]
Parte 2:
Spoiler
A rope snaps! Suddenly, the river is getting a lot closer than you remember. The bridge is still there, but some of the ropes that broke are now whipping toward you as you fall through the air!

The ropes are moving too quickly to grab; you only have a few seconds to choose how to arch your body to avoid being hit. Fortunately, your simulation can be extended to support longer ropes.

Rather than two knots, you now must simulate a rope consisting of ten knots. One knot is still the head of the rope and moves according to the series of motions. Each knot further down the rope follows the knot in front of it using the same rules as before.

Using the same series of motions as the above example, but with the knots marked H, 1, 2, ..., 9, the motions now occur as follows:

== Initial State ==

......
......
......
......
H.....  (H covers 1, 2, 3, 4, 5, 6, 7, 8, 9, s)

== R 4 ==

......
......
......
......
1H....  (1 covers 2, 3, 4, 5, 6, 7, 8, 9, s)

......
......
......
......
21H...  (2 covers 3, 4, 5, 6, 7, 8, 9, s)

......
......
......
......
321H..  (3 covers 4, 5, 6, 7, 8, 9, s)

......
......
......
......
4321H.  (4 covers 5, 6, 7, 8, 9, s)

== U 4 ==

......
......
......
....H.
4321..  (4 covers 5, 6, 7, 8, 9, s)

......
......
....H.
.4321.
5.....  (5 covers 6, 7, 8, 9, s)

......
....H.
....1.
.432..
5.....  (5 covers 6, 7, 8, 9, s)

....H.
....1.
..432.
.5....
6.....  (6 covers 7, 8, 9, s)

== L 3 ==

...H..
....1.
..432.
.5....
6.....  (6 covers 7, 8, 9, s)

..H1..
...2..
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

.H1...
...2..
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

== D 1 ==

..1...
.H.2..
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

== R 4 ==

..1...
..H2..
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

..1...
...H..  (H covers 2)
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

......
...1H.  (1 covers 2)
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

......
...21H
..43..
.5....
6.....  (6 covers 7, 8, 9, s)

== D 1 ==

......
...21.
..43.H
.5....
6.....  (6 covers 7, 8, 9, s)

== L 5 ==

......
...21.
..43H.
.5....
6.....  (6 covers 7, 8, 9, s)

......
...21.
..4H..  (H covers 3)
.5....
6.....  (6 covers 7, 8, 9, s)

......
...2..
..H1..  (H covers 4; 1 covers 3)
.5....
6.....  (6 covers 7, 8, 9, s)

......
...2..
.H13..  (1 covers 4)
.5....
6.....  (6 covers 7, 8, 9, s)

......
......
H123..  (2 covers 4)
.5....
6.....  (6 covers 7, 8, 9, s)

== R 2 ==

......
......
.H23..  (H covers 1; 2 covers 4)
.5....
6.....  (6 covers 7, 8, 9, s)

......
......
.1H3..  (H covers 2, 4)
.5....
6.....  (6 covers 7, 8, 9, s)

Now, you need to keep track of the positions the new tail, 9, visits. In this example, the tail never moves, and so it only visits 1 position. However, be careful: more types of motion are possible than before, so you might want to visually compare your simulated rope to the one above.

Here's a larger example:

R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20

These motions occur as follows (individual steps are not shown):

== Initial State ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........H..............  (H covers 1, 2, 3, 4, 5, 6, 7, 8, 9, s)
..........................
..........................
..........................
..........................
..........................

== R 5 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........54321H.........  (5 covers 6, 7, 8, 9, s)
..........................
..........................
..........................
..........................
..........................

== U 8 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
................H.........
................1.........
................2.........
................3.........
...............54.........
..............6...........
.............7............
............8.............
...........9..............  (9 covers s)
..........................
..........................
..........................
..........................
..........................

== L 8 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
........H1234.............
............5.............
............6.............
............7.............
............8.............
............9.............
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................

== D 3 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
.........2345.............
........1...6.............
........H...7.............
............8.............
............9.............
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................

== R 17 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
................987654321H
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................

== D 10 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........s.........98765
.........................4
.........................3
.........................2
.........................1
.........................H

== L 25 ==

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
H123456789................

== U 20 ==

H.........................
1.........................
2.........................
3.........................
4.........................
5.........................
6.........................
7.........................
8.........................
9.........................
..........................
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................

Now, the tail (9) visits 36 positions (including s) at least once:

..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
#.........................
#.............###.........
#............#...#........
.#..........#.....#.......
..#..........#.....#......
...#........#.......#.....
....#......s.........#....
.....#..............#.....
......#............#......
.......#..........#.......
........#........#........
.........########.........

Simulate your complete series of motions on a larger rope with ten knots. How many positions does the tail of the rope visit at least once?
[cerrar]

Y aquí va mi solución en Python:
Código: [Seleccionar]
import numpy as np

with open("input9.txt") as f:
    moves = [(x.split()[0], int(x.split()[1])) for x in f.read().splitlines()]
   
dict_moves = {'L':np.array([-1,0]), 'R':np.array([1,0]), 'U':np.array([0,1]), 'D':np.array([0,-1])}

def iterate(knots, move):
    knots[0] += dict_moves[move[0]]
    for i in range(1,len(knots)):
        if np.max(np.abs(knots[i-1]-knots[i])) > 1:
            knots[i] += np.sign(knots[i-1]-knots[i])
    return knots

def solve(moves, knots):
    pos = [(knots[len(knots)-1][0], knots[len(knots)-1][1])]
    for move in moves:
        for i in range(move[1]):
            knots = iterate(knots, move[0])
            pos.append((knots[len(knots)-1][0], knots[len(knots)-1][1]))
    return len(set(pos))

# Part 1
knots = [np.array([0,0]) for i in range(2)]
print(solve(moves, knots))

# Part 2
knots = [np.array([0,0]) for i in range(10)]
print(solve(moves, knots))

Hoy estoy bastante contento con mi código, creo que ha quedado una solución bastante concisa. Eso sí, por primera vez en este año la ejecución no es (prácticamente) instantánea. Me tarda 0,33s en la primera parte y alrededor de 2s en la segunda parte. Si podéis, cuando resolváis el problema comentad también sobre los tiempos.

Saludos
La ecuación más bonita de las matemáticas: \( d^2=0 \)

09 Diciembre, 2022, 06:32 pm
Respuesta #1

Eparoh

  • $$\Large \color{#c88359}\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 981
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Hola.

Veo que al final aunque el foro haya conspirado contra nosotros podemos seguir adelante  :laugh:

Dejo mi solución en Maple y Excel:

Código: [Seleccionar]
F:=readdata(cat(currentdir(),"\\Template 9.txt"),[string, integer]):
pos_in:=[0,0]:

Mov_H:=proc(mov,pos)
      if mov=" " then
         RETURN(pos);
      elif mov="R" then
         RETURN(pos+[1,0]);
      elif mov="L" then
         RETURN(pos+[-1,0]);
      elif mov="U" then
         RETURN(pos+[0,1]);
      else
         RETURN(pos+[0,-1]);
      fi;
end:
Mov_T:=proc(posH,posT)
      if max(map(abs,posH-posT))>1 then
            RETURN(posT+map(x-> if abs(x)>1 then x/2 else x fi,posH-posT));       
      else
         RETURN(posT);
      fi;
end:
Camino:=proc(F,pos_0,n)
   local N, pos, pos_aux, visit, i, j, k, mov;
      N:=nops(F);
      pos:=[seq(pos_0,i=1..n+1)];
      visit:={pos_0};
      for i from 1 to N do
         for j from 1 to F[i][2] do
            pos[1]:=Mov_H(F[i][1],pos[1]);
            for k from 2 to n+1 do
               pos[k]:=Mov_T(pos[k-1],pos[k]);
            od;
            visit:=visit union {pos[n+1]};
         od;
      od;
   RETURN(visit);
end:

nops(Camino(F,pos_in,1));
nops(Camino(F,pos_in,9));

Si no me equivoco hemos dado prácticamente la misma resolución (al menos a simple vista, la forma de iterar y los bucles me parecen casi iguales, pero tal vez me confunda en algo), pero curiosamente a mi el segundo me lo resuelve algo más rápido que el primero, no tengo ni idea de por qué  ???
Los tiempos son de aproximadamente 1.55 s el primero y 1.35 s el segundo.

EDITO: Creo que ya se porque me funciona más rápido el segundo. Supongo que es porque el último nudo se mantiene en la misma posición durante mucho más tiempo y por tanto el tamaño del conjunto de todos los puntos por los que pasa es menor (es el único conjunto que guardo, de los demás nudos no guardo su posición), y supongo que esto permitirá computar más rápido que al tener en memoria un conjunto enorme.

Un saludo.

09 Diciembre, 2022, 06:52 pm
Respuesta #2

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Veo que al final aunque el foro haya conspirado contra nosotros podemos seguir adelante  :laugh:
Sí. :laugh:
Llevo desde las 11 de la mañana intentando poner el mensaje y no había manera. Al final he enviado un mensaje privado a Diego Andrés y lo ha solucionado en un momento.

Citar
Si no me equivoco hemos dado prácticamente la misma resolución (al menos a simple vista, la forma de iterar y los bucles me parecen casi iguales, pero tal vez me confunda en algo), pero curiosamente a mi el segundo me lo resuelve algo más rápido que el primero, no tengo ni idea de por qué  ???
Los tiempos son de aproximadamente 1.55 s el primero y 1.35 s el segundo.
Sí, son clavadas diría yo, salvo porque uso la función np.sign. He mejorado un poco el programa (lo pensé antes, pero en el primer mensaje he dejado lo que tenía esta mañana porque ya tenía el mensaje escrito), porque antes usaba una lista para guardar las posiciones y luego lo pasaba a conjunto (básicamente porque los np.array no pueden ser elementos de un conjunto y lo tenía planteado inicialmente de otra forma), pero lo he pasado a usar un conjunto directamente y los tiempos mejoran algo. Ahora me sale \( 0,27s \) en la primera parte y \( 1,70s \) en la segunda. Aún así la segunda tuya es más rápida. Imagino que Maple debe ser más rápido que Python.

Dejo el programa con la pequeña modificación:
Código: [Seleccionar]
import numpy as np

with open("input9.txt") as f:
    moves = [(x.split()[0], int(x.split()[1])) for x in f.read().splitlines()]
   
dict_moves = {'L':np.array([-1,0]), 'R':np.array([1,0]), 'U':np.array([0,1]), 'D':np.array([0,-1])}

def iterate(knots, move):
    knots[0] += dict_moves[move[0]]
    for i in range(1,len(knots)):
        if np.max(np.abs(knots[i-1]-knots[i])) > 1:
            knots[i] += np.sign(knots[i-1]-knots[i])
    return knots

def solve(moves, knots):
    pos = set([(knots[len(knots)-1][0], knots[len(knots)-1][1])])
    for move in moves:
        for i in range(move[1]):
            knots = iterate(knots, move[0])
            pos.add((knots[len(knots)-1][0], knots[len(knots)-1][1]))
    return len(pos)

# Part 1
#st = time()
knots = [np.array([0,0]) for i in range(2)]
print(solve(moves, knots))

# Part 2
knots = [np.array([0,0]) for i in range(10)]
print(solve(moves, knots))
La ecuación más bonita de las matemáticas: \( d^2=0 \)

10 Diciembre, 2022, 02:16 pm
Respuesta #3

Eparoh

  • $$\Large \color{#c88359}\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 981
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Hola.

Sí, son clavadas diría yo, salvo porque uso la función np.sign.

Cierto, yo también pense en utilizarla, pero en Maple la función signo asigna al \( 0 \) el valor \( 1 \) por lo que no servía.

He mejorado un poco el programa (lo pensé antes, pero en el primer mensaje he dejado lo que tenía esta mañana porque ya tenía el mensaje escrito), porque antes usaba una lista para guardar las posiciones y luego lo pasaba a conjunto (básicamente porque los np.array no pueden ser elementos de un conjunto y lo tenía planteado inicialmente de otra forma), pero lo he pasado a usar un conjunto directamente y los tiempos mejoran algo. Ahora me sale \( 0,27s \) en la primera parte y \( 1,70s \) en la segunda. Aún así la segunda tuya es más rápida. Imagino que Maple debe ser más rápido que Python.

Supongo que Maple es más rápido sí, porque si no, poco sentido tiene que la segunda mía sea más rápida que tu mejora :P

Un saludo.