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

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

08 Diciembre, 2022, 12:58 pm
Leído 981 veces

geómetracat

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

Los enunciados de hoy (Treetop Tree House) son los siguientes.
Parte 1:
Spoiler
The expedition comes across a peculiar patch of tall trees all planted carefully in a grid. The Elves explain that a previous expedition planted these trees as a reforestation effort. Now, they're curious if this would be a good location for a tree house.

First, determine whether there is enough tree cover here to keep a tree house hidden. To do this, you need to count the number of trees that are visible from outside the grid when looking directly along a row or column.

The Elves have already launched a quadcopter to generate a map with the height of each tree (your puzzle input). For example:

30373
25512
65332
33549
35390

Each tree is represented as a single digit whose value is its height, where 0 is the shortest and 9 is the tallest.

A tree is visible if all of the other trees between it and an edge of the grid are shorter than it. Only consider trees in the same row or column; that is, only look up, down, left, or right from any given tree.

All of the trees around the edge of the grid are visible - since they are already on the edge, there are no trees to block the view. In this example, that only leaves the interior nine trees to consider:

    The top-left 5 is visible from the left and top. (It isn't visible from the right or bottom since other trees of height 5 are in the way.)
    The top-middle 5 is visible from the top and right.
    The top-right 1 is not visible from any direction; for it to be visible, there would need to only be trees of height 0 between it and an edge.
    The left-middle 5 is visible, but only from the right.
    The center 3 is not visible from any direction; for it to be visible, there would need to be only trees of at most height 2 between it and an edge.
    The right-middle 3 is visible from the right.
    In the bottom row, the middle 5 is visible, but the 3 and 4 are not.

With 16 trees visible on the edge and another 5 visible in the interior, a total of 21 trees are visible in this arrangement.

Consider your map; how many trees are visible from outside the grid?
[cerrar]
Parte 2:
Spoiler
Content with the amount of tree cover available, the Elves just need to know the best spot to build their tree house: they would like to be able to see a lot of trees.

To measure the viewing distance from a given tree, look up, down, left, and right from that tree; stop if you reach an edge or at the first tree that is the same height or taller than the tree under consideration. (If a tree is right on the edge, at least one of its viewing distances will be zero.)

The Elves don't care about distant trees taller than those found by the rules above; the proposed tree house has large eaves to keep it dry, so they wouldn't be able to see higher than the tree house anyway.

In the example above, consider the middle 5 in the second row:

30373
25512
65332
33549
35390

    Looking up, its view is not blocked; it can see 1 tree (of height 3).
    Looking left, its view is blocked immediately; it can see only 1 tree (of height 5, right next to it).
    Looking right, its view is not blocked; it can see 2 trees.
    Looking down, its view is blocked eventually; it can see 2 trees (one of height 3, then the tree of height 5 that blocks its view).

A tree's scenic score is found by multiplying together its viewing distance in each of the four directions. For this tree, this is 4 (found by multiplying 1 * 1 * 2 * 2).

However, you can do even better: consider the tree of height 5 in the middle of the fourth row:

30373
25512
65332
33549
35390

    Looking up, its view is blocked at 2 trees (by another tree with a height of 5).
    Looking left, its view is not blocked; it can see 2 trees.
    Looking down, its view is also not blocked; it can see 1 tree.
    Looking right, its view is blocked at 2 trees (by a massive tree of height 9).

This tree's scenic score is 8 (2 * 2 * 1 * 2); this is the ideal spot for the tree house.

Consider each tree on your map. What is the highest scenic score possible for any tree?
[cerrar]

Mi solución en Python:
Código: [Seleccionar]
import numpy as np

with open("input8.txt") as f:
    inp = f.read().splitlines()

matrix = np.array([[int(x) for x in line] for line in inp])

# Part 1
def left_max(matrix):
    max_matrix = np.zeros(matrix.shape)
    for i in range(matrix.shape[0]):
        great = -1
        for j in range(matrix.shape[1]):
            max_matrix[i, j] = great
            if matrix[i, j] > great:
                great = matrix[i, j]
    return max_matrix

def visible_heights(matrix):
    left = left_max(matrix)
    up = left_max(matrix.transpose()).transpose()
    right = np.flip(left_max(np.flip(matrix)))
    down = np.flip(left_max(np.flip(matrix).transpose())).transpose()
    return np.minimum.reduce([left, up, right, down])

def is_visible(matrix):
    visibility = visible_heights(matrix)
    return visibility < matrix

def count_trees(matrix):
    return is_visible(matrix).sum()

print(count_trees(matrix))

# Part 2
def distance_right(matrix, pos):
    height = matrix[pos[0], pos[1]]
    count = 0
    for j in range(pos[1]+1, matrix.shape[1]):
        count +=1
        if matrix[pos[0], j] >= height:
            break
    return count

def scenic_score(matrix, pos):
    right = distance_right(matrix, pos)
    down = distance_right(matrix.transpose(), (pos[1], pos[0]))
    left = distance_right(np.flip(matrix, 1), (pos[0], matrix.shape[1] - 1 - pos[1]))
    up = distance_right(np.flip(matrix, 0).transpose(), (pos[1], matrix.shape[0] - 1 - pos[0]))
    return up*down*left*right

def all_scores(matrix):
    scores = np.zeros(matrix.shape)
    for i in range(matrix.shape[0]):
        for j in range(matrix.shape[1]):
            scores[i,j] = scenic_score(matrix, (i,j))
    return scores

print(np.max(all_scores(matrix)))

Si ayer teníamos el típico problema de árboles del AoC, hoy tenemos el típico problema de rejillas/matrices. Mi solución es más complicada de la cuenta, pero la verdad es que tenía ganas de jugar con NumPy y he aprovechado para aprender varios métodos para rotar y reflejar matrices de todas las maneras posibles.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

08 Diciembre, 2022, 06:39 pm
Respuesta #1

w a y s

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 256
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
  • I
Hola,

aún no he resuelto el problema del día anterior, no sé muy bien como voy a plantear la solución, pero de momento tengo resuelto el de hoy, mi solución en java:

Código: [Seleccionar]
package aoc_2022;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Day8 {
    private static final File INPUT = new File("2022_inputs/2022_day8_input.txt");

    private int [][] matrix;
    private int rows, colums, counter;

    private List<Integer> trees;

    Day8(){
        this.colums = getColums();
        this.rows = getRows();
        this.matrix = getMatrix();
        this.counter = 0;
        trees = new ArrayList<>();
    }

    private int getColums(){
        int colums = 0;
        try(BufferedReader br = new BufferedReader(new FileReader(INPUT))){
            colums = br.readLine().length();
        }catch (IOException e){
            System.err.println("Error getting number of colums");
        }
        return colums;
    }

    private int getRows(){
        int rows = 0;
        String line = "";
        try(BufferedReader br = new BufferedReader(new FileReader(INPUT))){
            while((line = br.readLine()) != null){
                rows++;
            }
        }catch(IOException e){
            System.err.println("Error getting number of rows.");
        }
        return rows;
    }

    private int [][] getMatrix(){
        String line = "";
        int r = 0;
        int [][] matrix = new int[rows][colums];
        try(BufferedReader br = new BufferedReader(new FileReader(INPUT))){
            while((line = br.readLine()) != null){
                for (int i = 0; i < line.length(); i++) {
                    matrix[r][i] = line.charAt(i) - '0';
                }
                r++;
            }
        }catch(IOException e){
            System.err.println("Error getting matrix.");
        }
        return matrix;
    }

    private void printMatrix(){
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                System.out.println(matrix[i][j]);
            }
        }
    }

    private boolean checkUp(int i, int j){
        int value = matrix[i][j];
        for (int k = i-1; k >= 0 ; k--) {
            if(matrix[k][j] >= value)
                return true;
        }
        return false;
    }

    private int checkUp2(int i, int j){
        int c = 0;
        int value = matrix[i][j];
        for (int k = i-1; k >= 0 ; k--) {
            c++;
            if(matrix[k][j] >= value) {
                return c;
            }
        }
        return c;
    }

    private boolean checkRight(int i, int j){
        int value = matrix[i][j];
        for (int k = j+1; k < matrix[0].length ; k++) {
            if(matrix[i][k] >= value)
                return true;
        }
        return false;
    }

    private int checkRight2(int i, int j){
        int c = 0;
        int value = matrix[i][j];
        for (int k = j+1; k < matrix[0].length ; k++) {
            c++;
            if(matrix[i][k] >= value)
                return c;
        }
        return c;
    }

    private boolean checkDown(int i, int j){
        int value = matrix[i][j];
        for (int k = i+1; k < matrix.length ; k++) {
            if(matrix[k][j] >= value)
                return true;
        }
        return false;
    }

    private int checkDown2(int i,int j){
        int c = 0;
        int value = matrix[i][j];
        for (int k = i+1; k < matrix.length ; k++) {
            c++;
            if(matrix[k][j] >= value)
                return c;
        }
        return c;
    }

    private boolean checkLeft(int i, int j){
        int value = matrix[i][j];
        for (int k = j-1; k >= 0 ; k--) {
            if(matrix[i][k] >= value)
                return true;
        }
        return false;
    }

    private int checkLeft2(int i, int j){
        int c = 0;
        int value = matrix[i][j];
        for (int k = j-1; k >= 0 ; k--) {
            c++;
            if(matrix[i][k] >= value)
                return c;
        }
        return c;
    }

    private void solve(){
        for (int i = 1; i <matrix.length-1 ; i++) {
            for (int j = 1; j < matrix[0].length-1; j++) {
                if(!checkUp(i,j) || !checkDown(i,j) || !checkRight(i,j) || !checkLeft(i,j))
                    this.counter++;
            }
        }
    }

    private void solvePart2(){
        int c = 0;
        for (int i = 1; i <matrix.length-1 ; i++) {
            for (int j = 1; j < matrix[0].length-1; j++) {
                c = checkUp2(i,j) * checkLeft2(i,j) * checkDown2(i,j) * checkRight2(i,j);
                trees.add(c);
            }
        }
    }

    public static void main(String[] args) {
        Day8 d8 = new Day8();
        d8.solve();
        System.out.println(d8.counter + ((2*d8.matrix.length + 2*d8.matrix[0].length)-4));
        d8.solvePart2();
        System.out.println(Collections.max(d8.trees));
    }
}


08 Diciembre, 2022, 07:38 pm
Respuesta #2

Eparoh

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

Mi solución en Maple (hoy no conseguí nada en Excel que no supusiera fórmulas enormes y utilizar más de 600 columnas  ::)):

Código: [Seleccionar]
F:=readdata(cat(currentdir(),"\\Template 8.txt"),string):
F:=Array([seq([seq(parse(F[i][j]),j=1..length(F[1]))],i=1..nops(F))]):

Visible:=proc(F,i,j)
   local dim;
      dim:=[upperbound(F)];
      if i=1 or i=dim[1] or j=1 or j=dim[2] then
         RETURN(1);
      elif max(F[1..i-1,j])<F[i,j] then
         RETURN(1);
      elif max(F[i+1..dim[1],j])<F[i,j] then
         RETURN(1);
      elif max(F[i,1..j-1])<F[i,j] then
         RETURN(1);
      elif max(F[i,j+1..dim[2]])<F[i,j] then
         RETURN(1);
      else
         RETURN(0);
      fi;
end:
Score:=proc(F,i,j)
   local dim, T, P;
      dim:=[upperbound(F)];
      if i=1 or i=dim[1] or j=1 or j=dim[2] then
         RETURN(0);
      else
         T:=[[1,op(convert(map(x-> if x>=F[i,j] then 1 else 0 fi ,F[i,..]),list)[2..dim[2]-1]),1],
             [1,op(convert(map(x-> if x>=F[i,j] then 1 else 0 fi ,F[..,j]),list)[2..dim[1]-1]),1]];
         P:=ListTools[Search](1,T[1][j+1..]);
         P:=P*ListTools[Search](1,ListTools[Reverse](T[1][1..j-1]));
         P:=P*ListTools[Search](1,T[2][i+1..]);
         P:=P*ListTools[Search](1,ListTools[Reverse](T[2][1..i-1]));
      fi;
   RETURN(P);
end:

add(x, x in Array([seq([seq(Visible(F,i,j),j=1..upperbound(F)[1])],i=1..upperbound(F)[1])]));
max(Array([seq([seq(Score(F,i,j),j=1..upperbound(F)[1])],i=1..upperbound(F)[1])]));

Hoy no estaba muy contento con mi solución porque pensaba que de algún modo ingenioso se podía evitar un doble bucle for y estuve un buen rato pensando en ello, pero viendo vuestras soluciones supongo que no es posible esto. Al menos no de forma evidente, con lo cual me conformo  :laugh:

Un saludo.

08 Diciembre, 2022, 11:56 pm
Respuesta #3

w a y s

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 256
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
  • I
Hoy no estaba muy contento con mi solución porque pensaba que de algún modo ingenioso se podía evitar un doble bucle for y estuve un buen rato pensando en ello, pero viendo vuestras soluciones supongo que no es posible esto. Al menos no de forma evidente, con lo cual me conformo  :laugh:

Una vez estuve pensando una forma para recorrer un matriz usando un solo bucle, encontre lo siguiente indagando en internet:

Código: [Seleccionar]
private void oneLoop(){
        for (int i = 0, j = 0; i < matrix.length ;) {
            System.out.println(matrix[i][j]);
            if(j == matrix[0].length-1){
                i++;
                j=0;
            }else
                j++;
        }
    }

09 Diciembre, 2022, 12:56 pm
Respuesta #4

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
No entiendo muy bien a qué te refieres con "evitar un doble bucle for". Un doble bucle es necesario para recorrer la matriz, pero sospecho que te refieres a otra cosa.
Por otro lado, estoy intentando abrir un tema con la solución de hoy, pero parece que el foro da problemas y no me deja abrir un tema nuevo.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

09 Diciembre, 2022, 02:02 pm
Respuesta #5

w a y s

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 256
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
  • I
Por otro lado, estoy intentando abrir un tema con la solución de hoy, pero parece que el foro da problemas y no me deja abrir un tema nuevo.

Una duda para resolver el problema de hoy,¿has supuesto que la cabeza empieza en el mismo punto que en el ejemplo?

Gracias por tu ayuda de antemano.

09 Diciembre, 2022, 04:11 pm
Respuesta #6

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Una duda para resolver el problema de hoy,¿has supuesto que la cabeza empieza en el mismo punto que en el ejemplo?

No sé si entiendo muy bien la pregunta. Yo he usado un sistema de coordenadas en el plano y he supuesto que tanto la cabeza como la cola (en la primera parte) empiezan en el punto (0,0).

Por cierto, sigo sin poder abrir un tema nuevo. Me sale "Error en la base de datos".
La ecuación más bonita de las matemáticas: \( d^2=0 \)

09 Diciembre, 2022, 06:21 pm
Respuesta #7

Eparoh

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

No entiendo muy bien a qué te refieres con "evitar un doble bucle for". Un doble bucle es necesario para recorrer la matriz, pero sospecho que te refieres a otra cosa.
Por otro lado, estoy intentando abrir un tema con la solución de hoy, pero parece que el foro da problemas y no me deja abrir un tema nuevo.

Con evitar el doble bucle me refería a que buscaba alguna forma de evitar tener que recorrer cada elemento de la matriz, porque pensaba que por la forma del problema tal vez había algún truco "sencillo" para eliminar muchos valores a visitar de golpe.

Una vez estuve pensando una forma para recorrer un matriz usando un solo bucle, encontre lo siguiente indagando en internet:

Código: [Seleccionar]
private void oneLoop(){
        for (int i = 0, j = 0; i < matrix.length ;) {
            System.out.println(matrix[i][j]);
            if(j == matrix[0].length-1){
                i++;
                j=0;
            }else
                j++;
        }
    }

Pero al final ahí tienes un doble bucle "camuflado"  :laugh:

Un saludo.

09 Diciembre, 2022, 06:36 pm
Respuesta #8

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Con evitar el doble bucle me refería a que buscaba alguna forma de evitar tener que recorrer cada elemento de la matriz, porque pensaba que por la forma del problema tal vez había algún truco "sencillo" para eliminar muchos valores a visitar de golpe.

Tendría que pensarlo un poco para dar una demostración formal, pero pondría la mano en el fuego por que eso es imposible. Al menos en un caso completamente general, estoy bastante seguro de que hay que comprobar toda la matriz.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

10 Diciembre, 2022, 02:10 pm
Respuesta #9

Eparoh

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

Tendría que pensarlo un poco para dar una demostración formal, pero pondría la mano en el fuego por que eso es imposible. Al menos en un caso completamente general, estoy bastante seguro de que hay que comprobar toda la matriz.

Yo también lo creo, pero como tampoco soy demasiado habil programando ni conozco muchos ejemplos, pensaba que tal vez algo se me escapaba  ::)
Aunque, ver una demostración formal, solo por ver la forma que tiene una demostración de dicho tipo, estaría genial la verdad  ;D

Un saludo