Ice Golf Challenge

24

El objetivo de este desafío es escribir un programa o función que devuelva la menor cantidad de golpes necesarios para completar un curso determinado.

Entrada

  • El diseño del curso se puede aprobar de la forma y el formato que prefiera. (leída desde la consola, aprobada como parámetro de entrada, leída desde un archivo o cualquier otro, cadena de varias líneas, matriz de cadenas, matriz de caracteres / bytes bidimensionales).
  • La posición inicial de la pelota y el hoyo también se pueden pasar como entrada, no es necesario analizarla desde la entrada. En los casos de prueba, se incluyen en el curso para asegurarse de que no haya confusión sobre la posición real.
  • Puede reasignar los caracteres de entrada a otra cosa, siempre que sean reconocibles como caracteres distintos (por ejemplo, caracteres ASCII imprimibles).

Salida

  • El programa debe devolver la puntuación más baja posible (la menor cantidad de golpes necesarios para alcanzar el hoyo) para cualquier curso aprobado como entrada en un formato sensible (cadena, entero, flotante o un haiku que describe el resultado)
  • Si el curso es imposible de superar, devuelva -1(o cualquier otro valor falso de su elección que no se devolvería para un curso imbatible).

Ejemplo:

En este ejemplo, las posiciones se anotan en base a 0, X / Y, de izquierda a derecha, de arriba hacia abajo, pero puede usar cualquier formato que desee ya que el resultado es completamente independiente del formato de todos modos.

Entrada:

###########
#     ....# 
#      ...# 
#  ~    . # 
# ~~~   . # 
# ~~~~    # 
# ~~~~    # 
# ~~~~  o # 
# ~~~~    # 
#@~~~~    # 
###########

Ball (Start-Position): 1/9
Hole (End-Position):   8/7

Salida:

8

Curso de ejemplo

Reglas y campos

El curso puede consistir en los siguientes campos:

  • '@' Ball - El comienzo del curso.
  • 'o' Hoyo - El objetivo del curso
  • '#' Muro : la bola se detendrá cuando golpee un muro
  • '~' Agua : debe evitarse
  • '.' Arena : la pelota se detendrá en la arena inmediatamente
  • ' ' Hielo : la bola continuará deslizándose hasta que golpee algo

Las reglas y restricciones básicas del juego:

  • La pelota no puede moverse en diagonal, solo izquierda, derecha, arriba y abajo.
  • La pelota no se detendrá frente al agua, solo frente a las paredes, en la arena y en el hoyo.
    • Los disparos al agua son inválidos / imposibles
    • La pelota se quedará en el hoyo, no se saltará sobre ella como si fuera hielo
  • El curso es siempre rectangular.
  • El curso siempre está bordeado por agua o paredes (no se requieren verificaciones de límites).
  • Siempre hay exactamente una bola y un hoyo.
  • No todos los cursos son posibles de superar.
  • Puede haber múltiples rutas que den como resultado la misma puntuación (la más baja).

Lagunas y condición ganadora

  • Las lagunas estándar están prohibidas
  • Los programas deben terminar
  • No puedes inventar reglas adicionales (golpear la pelota con tanta fuerza que salta sobre el agua, rebota en una pared, salta sobre campos de arena, curvas alrededor de las esquinas, etc.)
  • Este es el , por lo que gana la solución con la menor cantidad de caracteres.
  • Las soluciones deben poder manejar todos los casos de prueba proporcionados; si esto es imposible debido a restricciones del idioma utilizado, especifíquelo en su respuesta.

Casos de prueba

Curso # 1 (2 golpes)

####
# @#
#o~#
####

Curso # 2 (no posible)

#####
#@  #
# o #
#   #
#####

Curso # 3 (3 golpes)

~~~
~@~
~.~
~ ~
~ ~
~ ~
~ ~
~.~
~o~
~~~

Curso # 4 (2 golpes)

#########
#~~~~~~~#
#~~~@~~~#
##  .  ##
#~ ~ ~ ~#
#~. o .~#
#~~~ ~~~#
#~~~~~~~#
#########

Curso # 5 (no posible)

~~~~~~~
~...  ~
~.@.~.~
~...  ~
~ ~ ~.~
~ . .o~
~~~~~~~

Más casos de prueba:

https://pastebin.com/Azdyym00

Manfred Radlwimmer
fuente
1
Relacionado: uno , dos .
AdmBorkBork
Si usamos una matriz de bytes bidimensional como entrada, ¿podemos usar una asignación personalizada para los símbolos?
Arnauld
@Arnauld No estoy seguro de cuál es el consenso habitual con respecto a eso aquí, pero diría que está bien siempre que la entrada aún sea reconocible. He actualizado la sección de entrada .
Manfred Radlwimmer
Si ingresa el destino directamente, ¿podemos requerir que el lugar de destino sea el símbolo de 'arena'?
l4m2
@ l4m2 Claro, de esa manera se mantendría consistente con todas las demás reglas.
Manfred Radlwimmer

Respuestas:

6

JavaScript (ES6), 174 bytes

Toma entrada en la sintaxis de curling curling([x, y])(a) , donde x e y son las coordenadas indexadas a 0 de la posición inicial y a [] es una matriz de enteros, con 0= hielo, 1= pared, 2= arena, 3= agujero y 4= agua

Devuelve 0si no hay solución.

p=>a=>(r=F=([x,y],n,R=a[y],c=R[x])=>R[c&(R[x]=4)|n>=r||[-1,0,1,2].map(d=>(g=_=>(k=a[v=Y,Y+=d%2][h=X,X+=~-d%2])||g())(X=x,Y=y)>3?0:k>2?r=-~n:F(k>1?[X,Y]:[h,v],-~n)),x]=c)(p)|r

Pruébalo en línea!

Comentado

p => a => (                       // given the starting position p[] and the matrix a[]
  r =                             // r = best result, initialized to a non-numeric value
  F = (                           // F = recursive function taking:
    [x, y],                       //   (x, y) = current position
    n,                            //   n = number of shots, initially undefined
    R = a[y],                     //   R = current row in the matrix
    c = R[x]                      //   c = value of the current cell
  ) =>                            //
    R[                            // this will update R[x] once the inner code is executed
      c & (R[x] = 4) |            //   set the current cell to 4 (water); abort if it was
      n >= r ||                   //   already set to 4 or n is greater than or equal to r
      [-1, 0, 1, 2].map(d =>      //   otherwise, for each direction d:
        (g = _ => (               //     g = recursive function performing the shot by
          k = a[                  //         saving a backup (h, v) of (X, Y)
            v = Y, Y += d % 2][   //         and updating (X, Y) until we reach a cell
            h = X, X += ~-d % 2]) //         whose value k is not 0 (ice)
          || g()                  //   
        )(X = x, Y = y)           //     initial call to g() with (X, Y) = (x, y)
        > 3 ?                     //     if k = 4 (water -> fail):
          0                       //       abort immediately
        :                         //     else:
          k > 2 ?                 //       if k = 3 (hole -> success):
            r = -~n               //         set r to n + 1
          :                       //       else:
            F(                    //         do a recursive call to F():
              k > 1 ?             //           if k = 2 (sand):
                [X, Y]            //             start the next shots from the last cell
              :                   //           else (wall):
                [h, v],           //             start from the last ice cell
              -~n                 //           increment the number of shots
            )                     //         end of recursive call
      ), x                        //   end of map(); x = actual index used to access R[]
    ] = c                         // restore the value of the current cell to c
)(p) | r                          // initial call to F() at the starting position; return r
Arnauld
fuente
5

Python 3 , 273 bytes

def p(g,c,d,k=0):
	while 1>k:c+=d;k=g.get(c,9)
	return-(k==2)or c-d*(k==3)
def f(g):
	c={q for q in g if g.get(q,9)>4};I=0;s=[c]
	while all(g.get(q,9)-4for q in c):
		c={k for k in{p(g,k,1j**q)for k in c for q in range(4)}if-~k}
		if c in s:return-1
		s+=[c];I+=1
	return I

Pruébalo en línea!

-41 bytes gracias a ovs
-1 byte gracias a Jonathan Frech

Hiperneutrino
fuente
No podría if k+1ser if-~k?
Jonathan Frech el
@ JonathanFrech sí, gracias
HyperNeutrino
2

C #, 461418 bytes

Esta es solo una implementación de referencia no competitiva para (con suerte) revivir este desafío:

Golfed por Kevin Cruijssen

int P(string[]C){int w=C[0].Length,i=0,l=c.Length;var c=string.Join("",C);var h=new int[l];for(var n=new List<int>();i<l;n.Add(i++))h[i]=c[i]!='@'?int.MaxValue:0;for(i=1;;i++){var t=n;n=new List<int>();foreach(int x in t){foreach(int d in new[]{-1,1,-w,w}){for(int j=x+d;c[j]==' ';j+=d);if(c[j]=='#'&h[j-d]>s){h[j-d]=s;n.Add(j-d);}if(c[j]=='.'&h[j]>s){h[j]=s;n.Add(j);}if(c[j]=='o')return s;}}if(n.Count<1)return -1;}}

Sin golf

int IceGolf(string[] course)
{
    // Width of the course
    int w = course[0].Length;

    // Course as single string
    var c = string.Join("", course);

    // Array of hits per field
    var hits = new int[c.Length];

    // Fields to continue from
    var nextRound = new List<int>();

    // Initialize hits
    for (int i = 0; i < hits.Length; i++)
    {
        if (c[i] != '@')
            // All fields start with a high value
            hits[i] = Int32.MaxValue;
        else
        {
            // Puck field starts with 0
            hits[i] = 0;
            nextRound.Add(i);
        }
    }

    for (int s = 1; ; s++)
    {
        // clear the fields that will be used in the next iteration
        var thisRound = nextRound;
        nextRound = new List<int>();

        foreach (int i in thisRound)
        {
            // test all 4 directions
            foreach (int d in new[] { -1, 1, -w, w })
            {
                int j = i+d;

                // ICE - slide along
                while (c[j] == ' ')
                    j += d;

                // WALL - stop on previous field
                if (c[j] == '#' && hits[j-d] > s)
                {
                    hits[j-d] = s;
                    nextRound.Add(j-d);
                }

                // SAND - stop
                if (c[j] == '.' && hits[j] > s)
                {
                    hits[j] = s;
                    nextRound.Add(j);
                }

                // HOLE return strikes
                if (c[j] == 'o')
                    return s;
            }
        }

        // No possible path found
        if (nextRound.Count == 0)
            return -1;
    }
}

Pruébalo en línea

Manfred Radlwimmer
fuente
1
Golfé un poco más: int P(string[]C){int w=C[0].Length,i=0,l=c.Length;var c=string.Join("",C);var h=new int[l];for(var n=new List<int>();i<l;n.Add(i++))h[i]=c[i]!='@'?int.MaxValue:0;for(i=1;;i++){var t=n;n=new List<int>();foreach(int x in t){foreach(int d in new[]{-1,1,-w,w}){for(int j=x+d;c[j]==' ';j+=d);if(c[j]=='#'&h[j-d]>s){h[j-d]=s;n.Add(j-d);}if(c[j]=='.'&h[j]>s){h[j]=s;n.Add(j);}if(c[j]=='o')return s;}}if(n.Count<1)return -1;}}(418 bytes). Además, ¿podría agregar un enlace TIO con código de prueba?
Kevin Cruijssen
Gracias por el enlace TIO. El código que proporcioné anteriormente no funcionó, así que lo arreglé y jugué tres bytes más. Pruébelo en línea 415 bytes . (Tendrá que volver a agregar su enorme caso de prueba nuevamente desde su TIO actual. No pude pegar el enlace en este comentario porque el enlace era demasiado grande con ese caso de prueba ...; p)
Kevin Cruijssen