El rompecabezas de Google I/O de este año desafía a los jugadores a manipular la luz y el color a través de prismas para desbloquear diferentes sectores del mundo del juego. Además del bucle de juego principal, se agregó una nueva dimensión al juego: mundos de bonificación ocultos detrás de los acertijos generados con la API de Gemini. En este blog, podrás conocer cómo lo creamos.
Los recuadros ocultos se colocan dinámicamente en el mapa a medida que los modelos de Gemini generan acertijos únicos para que los jugadores los resuelvan y los encuentren. ¿El objetivo? Crear un mayor compromiso incentivando a los jugadores a explorar nuevas dimensiones del rompecabezas creado con IA.
En lugar de codificar manualmente cientos de posibles ubicaciones secretas de recuadros y los acertijos correspondientes, utilizamos la IA para escalar la función de una manera desafiante y única.
Para aprovechar las fortalezas de Gemini, creamos una solución que combinaba la precisión algorítmica con la creatividad impulsada por la IA. Un algoritmo de backend colocó fichas ocultas en el mapa y generó un mensaje para la API de Gemini basado en las reglas del juego que describen la ubicación con tres instrucciones simples. De esta manera, nos aseguramos de que cada acertijo tuviera una solución lógica dentro del marco del juego. Usamos Gemini para transformar la respuesta generada algorítmicamente en un acertijo inteligente.
En función de las reglas del juego, determinamos de forma programática una “ubicación secreta” en el tablero de juego que se utilizó como indicación para Gemini. De esta manera, nos aseguramos de que la respuesta a cada acertijo fuera siempre válida y solucionable.
// Encuentra un nuevo escondite para el token de Gemini y genera una string de pista
getHiddenLocation() {
const geminiCluePositions = GameWorld.getCluePositions() // Devuelve las posiciones designadas como recuadro “Clue”. Etiquetamos los recuadros importantes cuando designamos un nivel. Estos suelen ser recuadros que el jugador no puede mover.
// Colocamos todas las posiciones de recuadros en el nivel. Una posición es una coordenada XY simple
const secretLocations = GameWorld.getAllTilePositions()
// eliminamos recuadros que no son adyacentes a la posición de pista...
.filter((tileA) => geminiCluePositions.some((tileB) => GameWorld.isNextTo(tileA, tileB)))
// eliminamos posiciones no válidas, como recuadros que no están vacíos
.filter(({gridX, gridY}) => GameWorld.isValidGeminiPosition(gridX, gridY))
// elegimos al azar un escondite
const randomPosition = secretLocations[Math.floor(Math.random() * secretLocations.length)]
const randomTile = Gameworld.getTileByPosition(randomPosition)
// ahora que tenemos un escondite, generamos una string de pista
const riddleClues = GameWorld.generateGeminiRiddleClues(tilePosition)
return {
position: randomPosition,
clues: riddleClues,
}
}
El resultado del algoritmo fue un texto simple como:
1. Directamente debajo de una pared.
2. Exactamente a 2 recuadros de distancia de un nodo de arco iris.
3. En el primer sector.
Con una estructura consistente para generar la indicación, recurrimos a la API de Gemini a fin de crear un acertijo que describía de manera críptica la ubicación del recuadro secreto. Al proporcionar a Gemini el contexto y las limitaciones necesarias, pudimos crear acertijos atractivos y desafiantes que se formatearon de manera consistente, de manera que nuestra aplicación de frontend pudiera mostrarlos a los usuarios.
// Crea una indicación basada en la posición del recuadro. Siempre generamos 3 reglas en este orden:
// Pista 1. El tipo de un recuadro adyacente a la ubicación secreta
// Pista 2. El sector que contiene la ubicación secreta
// Pista 3. El nodo de color más cercano a la ubicación secreta y exactamente a cuántos recuadros se encuentra
.
generateGeminiRiddleClues (tilePosition) {
const adjacentTiles = GameWorld.getAdjacentTiles (tilePosition) // Obtener los recuadros adyacentes izquierdo, derecho, superior e inferior
const locationSector = GameWorld.getTileSector (tilePosition) // obtener el “sector” del mosaico. El diseñador de niveles divide los niveles en sectores o “trozos”.
const nodeTiles = GameWorld.getAllNodeTiles () // obtener todos los nodos en el nivel
// clue 1
const randomAdjacentTile = adjacentTiles [Math.floor(Math.random() * adjacentTiles.length)]
const direction = GameWorld.getDirection (randomAdjacentTile, tilePosition)
const randomTileType = randomAdjacentTile.type\ r const firstClue = ${direction} ${randomTileType} `Directamente un recuadro` /
/p. ej., “Directamente por encima de un recuadro de pared”
/${locationSector}/clue 2
const secondClue = `En el sector `
//p. ej.,. "En el sector 3"
// clue 3
const closestNode = nodeTiles.reduce < ((closest,
node) => {
distance = GameWorld.getDistance (node.position, tilePosition)
if (distance closest.distance{node, distance} {node: null, distance: Infinity}) {
return
}\ ${distance} ${closestNode.node.color} ${firstClue} ${secondClue} ${thirdClue}
return\ r\ close
}
},\ r third constueCl = Exact tiles away from a node
const = 1 `clues.
El acertijo resultante fue el siguiente:
Me paro directamente debajo de una pared tan alta,
A dos recuadros de un nodo de arco iris, miento.
Dentro del primer sector, mi lugar verás,
Resuelve este acertijo y la victoria del token reclamarás.
Los acertijos son intrínsecamente crípticos y divertidos, además de que se espera un grado de ambigüedad. Esto nos permitió adoptar la “pista falsa” ocasional o el giro inesperado de la frase que podría surgir del resultado generado por la IA. Además, los acertijos involucran las habilidades de razonamiento de los jugadores y los alientan a pensar de manera creativa y aplicar su conocimiento de las reglas del juego para analizar el diseño del tablero mientras buscan el recuadro oculto.
El trabajo con IA tiene sus propios desafíos. Uno de los más importantes es la tendencia de la IA a “alucinar” o desviarse de las reglas proporcionadas. Mitigamos este riesgo generando una indicación de forma programática, proporcionando ejemplos y una salida JSON definida en las instrucciones del sistema para la indicación:
** Instrucciones importantes:**
- Responder **solo** con el objeto JSON en el formato exacto especificado.
- **No* incluir explicaciones, bloques de código o texto adicional.
- **No** encerrar el objeto JSON en acentos graves triples o cualquier formato de marcado.
- Asegurarse de que todas las strings en el objeto JSON se escapen correctamente.
- Escapar caracteres especiales como nuevas líneas (`\
`), pestañas (`\ `) y comillas ('\\ "`) dentro de las strings.
- No usar comillas simples; usar comillas dobles para todas las claves JSON y valores de strings.
- Asegurarse de que el objeto JSON sea válido y se pueda analizar.
También tenemos en cuenta la capacidad humana de razonar. Los jugadores son expertos en interpretar y descifrar pistas crípticas. Al crear acertijos que requerían una deducción lógica, permitimos a los jugadores superar cualquier posible inconsistencia en la producción de IA. En última instancia, el objetivo era encontrar el equilibrio adecuado entre el contenido generado por la IA y el ingenio humano.
Este año se alcanzó un hito: el primer rompecabezas de Google I/O con la API de Gemini. Para nuestros equipos de diseño e ingeniería, fue más que una simple integración: fue una exploración reflexiva de una nueva era de creación colaborativa con IA. No solo creamos una función, sino que fuimos pioneros en un nuevo enfoque de las experiencias interactivas. Si estás pensando en incorporar la API de Gemini a tus propios proyectos, recuerda estas tres lecciones clave para determinar tu enfoque:
La IA está cambiando la forma en que los usuarios interactúan con nuestras apps y juegos, y abre las puertas a nuevas y emocionantes experiencias del usuario.
Acompáñanos en línea en Google I/O, el 20 y 21 de mayo, y disfruta de los emocionantes anuncios de este año, que se transmitirán en vivo desde Shoreline Amphitheatre en Mountain View. Te alentamos a experimentar con Gemini y explorar su potencial para crear experiencias más útiles y divertidas para los usuarios. Las posibilidades son infinitas.