El sistema de fabricación en Minecraft utiliza una cuadrícula de 2x2 o 3x3. Coloca los ingredientes en la cuadrícula, y si coloca los ingredientes correctos en el patrón correcto, se activará la receta.
Algunos puntos interesantes sobre el diseño:
- Algunas recetas pueden intercambiar ciertos ingredientes por otros. Por ejemplo, un pico usa palos para el mango y puede usar tablas de madera, adoquines, lingotes de hierro, lingotes de oro o gemas de diamantes para la cabeza.
- La posición relativa dentro del patrón es lo que importa, no la posición absoluta en la cuadrícula. Es decir, puede crear una antorcha colocando el palo y el carbón (o carbón) en el patrón correcto en cualquiera de las seis posiciones en la cuadrícula de 3x3.
- Los patrones pueden voltearse horizontalmente.
Puede que esté pensando demasiado, pero esto parece un problema interesante de búsqueda / reducción de conjuntos. Entonces, ¿cómo funciona (o podría) funcionar esto, algorítmicamente hablando?
minecraft-modding
patterns
search
David Eyk
fuente
fuente
Respuestas:
Otra solución es usar un árbol algo complicado. Los nodos de rama en su árbol se crearían iterando sobre la receta (una vez más usando
for (y) { for (x) }
); Esta es su estructura de árbol estándar estándar. Su nodo final contendría una estructura adicional (Dictionary
/HashMap
) que asigna dimensiones a recetas.Esencialmente, lo que busca es esto:
Los nodos negros son sus ramas que indican el tipo de elemento; los rojos son sus hojas (terminadores) que le permiten diferenciar el tamaño / orientación.
Para buscar sobre este árbol, primero encontrará el cuadro delimitador (como se describe en mi primera respuesta ) y luego iterará sobre los nodos en el mismo orden que atraviesa el árbol a medida que avanza. Finalmente, simplemente buscaría la dimensión en su
Dictionary
oHashMap
y obtendría el resultado de la receta.Solo por diversión fui e implementé esto , lo que probablemente aclarará mi respuesta. Además : me doy cuenta de que esta es una respuesta diferente, y con razón: es una solución diferente.
fuente
Debe recordar que Minecraft solo usa un conjunto muy pequeño de posibles recetas, por lo que no hay necesidad de nada tan inteligente.
Dicho esto, lo que haría es encontrar la cuadrícula más pequeña que se ajuste (es decir, ignorar las filas y columnas vacías para averiguar si es una 2x2 o 3x3, o 2x3 (puerta)). Luego recorra la lista de recetas con ese tamaño, simplemente verificando si el tipo de elemento es el mismo (es decir, en el peor de los casos, 9 comparaciones enteras en Minecraft, ya que usa una identificación de tipo entero para elementos y bloques) y deténgase cuando encuentre una coincidencia.
De esta manera también hace que la posición relativa de los elementos sea irrelevante (puede colocar una antorcha en cualquier lugar de la cuadrícula de fabricación y funcionará porque lo ve como una caja de 1x2, no una caja de 3x3 que está principalmente vacía).
Si tiene una gran cantidad de recetas, por lo que hacer una búsqueda lineal a través de las posibles coincidencias lleva mucho tiempo, sería posible ordenar la lista y hacer una búsqueda binaria (O (log (N)) vs O (N)). Esto ocasionaría un trabajo adicional en la creación de la lista, pero esto se puede hacer al inicio una vez y mantenerse en la memoria después.
También una última cosa, para permitir voltear la receta horizontalmente más simple sería simplemente agregar la versión reflejada a la lista.
Si desea hacerlo sin agregar una segunda receta, puede verificar si la receta de entrada tiene un elemento en [0,0] con una identificación más alta que en [0,2] (o [0,1] para 2x2, no es necesario verificarlo) para 1x2 y, de ser así, duplíquelo, si no, continúe verificando la siguiente fila hasta llegar al final. Con esto también debe asegurarse de que las recetas se agreguen en la rotación correcta.
fuente
Ver si una determinada configuración de cuadrícula coincide con una determinada receta es simple si codifica la cuadrícula de 3x3 como una cadena y utiliza una coincidencia de expresión regular . Acelerar la búsqueda es un asunto diferente, del que hablaré al final. Siga leyendo para obtener más información.
Paso 1) Codificar la cuadrícula como cadena
Simplemente asigne una identificación de carácter a cada tipo de celda y concatene todo lado a lado en este orden:
Y como un ejemplo más concreto, considere la receta del palo, donde W representa madera y E es una celda vacía (simplemente podría usar un carbón vacío ''):
Paso 2) Haga coincidir la receta con expresión regular (o cadena. Contiene un poco de procesamiento en los datos)
Continuando con el ejemplo anterior, incluso si movemos la formación, todavía hay un patrón en la cadena (WEEW rellenado por E en ambos lados):
Entonces, no importa dónde mueva el palo, seguirá coincidiendo con la siguiente expresión regular:
/^E*WEEWE*$/
Las expresiones regulares también le permiten realizar el comportamiento condicional que mencionó. Por ejemplo (receta inventada), si desea un pico hecho de hierro o piedra para dar el mismo resultado, es decir:
Puede combinar ambos en la expresión regular:
/^(III)|(SSS)EWEEWE$/
Los volteos horizontales también se pueden agregar con la misma facilidad (utilizando también el operador |).
Editar: De todos modos, la parte regex no es estrictamente necesaria. Es solo una forma de encapsular el problema en una sola expresión. Pero para el problema de ubicación variable, también podría recortar la cadena de la cuadrícula de cualquier espacio de relleno (o E en este ejemplo) y hacer un String.Contains (). Y para el problema de ingredientes múltiples o las recetas duplicadas, puede manejarlas todas como recetas múltiples (es decir, separadas) con el mismo resultado.
Paso 3) Acelerar la búsqueda
En cuanto a la reducción de la búsqueda, deberá crear una estructura de datos para agrupar las recetas y ayudar con la búsqueda. Tratar la cuadrícula como una cadena tiene algunas ventajas aquí también :
Podría definir la "longitud" de una receta como la distancia entre el primer carácter no vacío y el último carácter no vacío. Un simple
Trim().Length()
le daría esta información. Las recetas pueden agruparse por longitud y almacenarse en un diccionario.o
Una definición alternativa de "longitud" podría ser el número de caracteres no vacíos. Nada más cambia. También podría agrupar recetas por este criterio.
Si el punto número 1 no es suficiente, las recetas también se pueden agrupar por el tipo del primer ingrediente que aparece en la receta. Esto sería tan simple como hacerlo
Trim().CharAt(0)
(y evitar que Trim resulte en una cadena vacía).Entonces, por ejemplo, almacenaría recetas en:
Y realice la búsqueda como algo así como:
fuente
No puedo decirte cómo funciona el Minecraft, aunque estoy seguro de que si miraste MCP (si tienes una copia legal de Minecraft) podrías averiguarlo.
Implementaría esto de la siguiente manera:
for (y) { for (x) }
).Entonces, por ejemplo, digamos que tenemos dos ingredientes; X e Y y espacios en blanco son *. Toma la siguiente receta:
Primero resolvemos el cuadro delimitador, cediendo
(2,0)-(2,2)
. Por lo tanto, nuestra clave se vería así[1][3]
(1 ancho, 3 alto). A continuación, recorremos cada elemento dentro del cuadro delimitador y agregamos la ID, por lo que la clave se convierte[1][3][X][Y][Y]
; luego, busque esto en su diccionario / DB y obtendrá el resultado de esa receta.Para explicar la independencia en el paso 2 más claramente, considere la siguiente receta:
La parte superior / izquierda está claramente en 0,0, sin embargo, el primer elemento que normalmente encontraría sería 0,1 o 1,0 (dependiendo de su ciclo). Sin embargo, si encuentra la primera columna no vacía, así como la primera fila no vacía y combina esas coordenadas, obtendrá 0,0: el mismo principio se aplica a la parte inferior / derecha del cuadro delimitador.
fuente
Así es como lo hice en Block Story:
fuente