올해의 Google I/O 퍼즐에서 플레이어는 프리즘을 통해 빛과 색을 조작하여 게임 세계 각 섹터의 과제를 해결해야 합니다. 핵심 게임 루프 외에도 게임플레이에 새로운 차원이 추가되었습니다. 바로 Gemini API로 생성된 수수께끼 뒤에 숨겨진 보너스 세계입니다. 이 블로그에서는 그걸 어떻게 만들었는지 살펴보겠습니다!
플레이어가 찾아서 풀 수 있는 독특한 수수께끼를 Gemini 모델이 생성함에 따라 지도에 숨겨진 타일이 동적으로 배치됩니다. 목표는 뭘까요? AI로 만들어진 퍼즐의 새로운 차원을 플레이어가 탐색하도록 인센티브를 제공하여 참여도를 높이는 것입니다.
가능한 수백 가지의 비밀 타일 위치와 그에 해당하는 수수께끼를 수동으로 하드코딩하는 대신, AI를 사용하여 도전적이고 독창적인 방식으로 이러한 기능을 확장할 수 있었습니다.
Gemini의 강점을 활용하기 위해 알고리즘 정밀도와 AI 기반 창의성을 결합한 솔루션을 고안했습니다. 백엔드 알고리즘은 지도에 숨겨진 타일을 배치하고 세 가지 간단한 지시문으로 위치를 설명하는 게임 규칙을 기반으로 Gemini API용 프롬프트를 생성했습니다. 이를 통해 모든 수수께끼가 게임의 프레임워크 내에서 논리적 해법을 갖도록 했습니다. Gemini를 사용해 알고리즘으로 생성된 답변을 기발한 수수께끼로 변환했습니다.
게임 규칙을 바탕으로 Gemini용 프롬프트로 사용된 게임 보드에서 "비밀 위치"를 프로그래밍 방식으로 정했습니다. 이를 통해 각 수수께끼에 대한 답을 항상 유효하고 해결 가능한 것이 되도록 할 수 있었습니다.
// Gemini 토큰을 위한 새로운 숨길 곳을 찾고 단서가 될 문자열을 생성합니다.
getHiddenLocation() {
const geminiCluePositions = GameWorld.getCluePositions() // 'Clue' 타일로 지정된 위치를 반환합니다. 레벨 디자인 시 중요한 타일에 태그를 지정합니다. 이러한 타일은 일반적으로 플레이어가 이동할 수 없는 타일입니다.
// 레벨의 모든 타일 위치를 얻습니다. 위치는 간단한 XY 좌표입니다.
const secretLocations = GameWorld.getAllTilePositions()
// 단서 위치와 인접하지 않은 타일을 제거합니다...
.filter((tileA) => geminiCluePositions.some((tileB) => GameWorld.isNextTo(tileA, tileB)))
// 비어 있지 않은 타일같이 잘못된 위치를 제거합니다.
.filter(({gridX, gridY}) => GameWorld.isValidGeminiPosition(gridX, gridY))
// 숨길 곳을 무작위로 선택합니다.
const randomPosition = secretLocations[Math.floor(Math.random() * secretLocations.length)]
const randomTile = Gameworld.getTileByPosition(randomPosition)
// 이제 숨길 곳이 있으므로 단서 문자열을 생성합니다.
const riddleClues = GameWorld.generateGeminiRiddleClues(tilePosition)
return {
position: randomPosition,
clues: riddleClues,
}
}
알고리즘에서 다음과 같은 간단한 텍스트가 출력되었습니다.
1. 벽 바로 아래.
2. 무지개 노드에서 정확히 타일 2개만큼 떨어져 있음.
3. 첫 번째 섹터에.
일관된 구조로 프롬프트가 생성되도록 한 다음, Gemini API를 사용하여 비밀 타일의 위치를 아리송하게 설명하는 수수께끼를 만들었습니다. 수수께끼를 만드는 데 필요한 컨텍스트와 제약 조건을 Gemini에 프롬프트로 제시하여 프런트 엔드 애플리케이션이 사용자에게 표시할 수 있는 방식으로 형식이 일관되게 지정된 매력적이고도 도전적인 수수께끼를 만들 수 있었습니다.
// 타일 위치를 기준으로 프롬프트를 작성합니다. 항상 다음 순서로 3가지 규칙을 출력합니다.
// 단서 1. 비밀 위치에 인접한 한 타일의 유형
// 단서 2. 비밀 위치가 포함된 섹터
// 단서 3. 비밀 위치에 가장 가까운 색상 노드와 정확히 몇 개의 타일만큼 떨어져 있는지.
generateGeminiRiddleClues(tilePosition) {
const adjacentTiles = GameWorld.getAdjacentTiles(tilePosition) // 왼쪽, 오른쪽, 위쪽, 아래쪽 이웃 타일을 가져옵니다.
const locationSector = GameWorld.getTileSector(tilePosition) // 타일의 '섹터'를 가져옵니다. 레벨은 레벨 디자이너에 의해 섹터 또는 '청크'로 나뉩니다.
const nodeTiles = GameWorld.getAllNodeTiles() // 레벨의 모든 '노드' 타일을 가져옵니다.
// 단서 1
const randomAdjacentTile = adjacentTiles[Math.floor(Math.random() * adjacentTiles.length)]
const direction = GameWorld.getDirection(randomAdjacentTile, tilePosition)
const randomTileType = randomAdjacentTile.type
const firstClue = `Directly ${direction} a ${randomTileType} tile` // 예: "벽 타일 바로 위"
// 단서 2
const secondClue = `In sector ${locationSector}` // 예: "섹터 3에"
// 단서 3
const closestNode = nodeTiles.reduce((closest, node) => {
const distance = GameWorld.getDistance(node.position, tilePosition)
if (distance < closest.distance) {
return {node, distance}
}
return closest
}, {node: null, distance: Infinity})
const thirdClue = Exactly ${distance} tiles away from a ${closestNode.node.color} node`
const clues = `1. ${firstClue}. 2. ${secondClue}. 3. ${thirdClue}.`
return clues
}
결과적으로 생성된 수수께끼는 다음과 같습니다.
나는 이렇게 높은 담벼락 바로 아래에 서 있어요.
나는 무지개 노드에서 2개의 타일만큼 떨어진 곳에 있어요.
첫 번째 섹터에서 내가 있는 곳을 보실 수 있어요.
이 수수께끼를 풀고 토큰의 승리를 차지하세요.
수수께끼는 본질적으로 아리송하고 재미있는 데다, 어느 정도의 모호성이 있는 게 당연합니다. 따라서 AI로 생성된 출력 결과로 인해 가끔 발생할 수 있는 '주의를 딴 데로 돌리는 요소' 또는 예기치 않은 문구도 자연스레 받아들일 수 있었습니다. 또한 수수께끼는 플레이어가 추론 실력을 동원해 창의적으로 생각하게 하고 게임 규칙에 대한 지식을 적용하도록 합니다. 이 과정에서 플레이어는 숨겨진 타일을 찾으면서 보드의 레이아웃을 분석하게 됩니다.
AI로 작업을 할 때에는 그에 따른 고유의 어려움이 있습니다. 가장 중요한 문제 중 하나는 AI가 할루시네이션을 하거나 제시된 규칙에서 벗어나는 경향입니다. 저희는 프롬프트를 프로그래밍 방식으로 생성하고 프롬프트에 대한 시스템 지시문에 예제와 정의된 JSON 출력을 제공하여 이러한 위험을 완화했습니다.
** 중요 지시문: **
- **오직** 지정된 정확한 형식의 JSON 객체로만 응답하세요.
- 설명, 코드 블록 또는 추가 텍스트를 포함하지 **마세요**.
- 삼중 백틱이나 마크다운 형식 지정으로 JSON을 감싸지 **마세요**.
- JSON의 모든 문자열이 올바르게 이스케이프되는지 확인하세요.
- 문자열 내의 줄 바꿈(`\\n`), 탭(`\\t`), 따옴표(`\\"`)와 같은 특수 문자를 이스케이프하세요.
- 모든 JSON 키와 문자열 값에는 작은따옴표를 사용하지 말고 큰따옴표를 사용하세요.
- JSON이 유효하고 구문 분석 가능한지 확인하세요.
저희는 인간의 추론 능력에도 기대었습니다. 플레이어는 아리송한 단서를 해석하고 해독하는 데 능숙합니다. 저희는 논리적 추론이 필요한 수수께끼를 만들어 플레이어가 AI 출력 결과의 잠재적 불일치를 극복할 수 있도록 했습니다. 궁극적으로, AI로 생성된 콘텐츠와 인간의 독창성 사이에서 적절한 균형을 찾는 것이 핵심이었습니다.
올해는 Gemini API를 특징으로 하는 최초의 Google I/O 퍼즐이라는 이정표를 세웠습니다. 디자인팀과 엔지니어링팀의 입장에서 그건 단순한 통합 그 이상이었습니다. 즉, AI와 협업하여 새로운 것을 만들어내는 새로운 시대에 대한 사려 깊은 탐구였습니다. 저희는 단순히 기능을 개발하는 것이 아니라 대화형 경험에 대한 새로운 접근 방식을 개척했습니다. Gemini API를 프로젝트에 도입하고자 고려 중이라면 접근 방식을 결정할 때 다음 세 가지 주요 교훈을 기억하세요.
AI는 사용자가 앱 및 게임과 상호 작용하는 방식을 변화시켜 새롭고 흥미로운 사용자 경험으로 가는 문을 열고 있습니다.
5월 20일부터 21일까지 열리는 Google I/O에 온라인으로 참여해 캘리포니아주 Mountain View의 Shoreline Amphitheatre에서 라이브 스트리밍으로 중계되는 올해의 흥미로운 발표를 지켜보세요. Gemini로 다양한 실험을 하면서 사용자에게 더 유용하고 재미있는 경험을 창출할 수 있는 잠재력을 탐색해 보시기 바랍니다. 가능성은 무궁무진합니다.