Os jogos de aventura em texto têm uma fórmula bem definida; existe um mundo composto por uma série de salas / espaços, o jogador pode se movimentar por essas salas e há alguns itens nas salas. Os itens podem ser apanhados pelo jogador, largados, usados para acessar outras salas (por exemplo, chaves) e combinados com outros itens para criar novos itens.
Desafio
Seu desafio é escrever um tempo de execução de aventura de texto no menor número de bytes (código de golfe). Para manter as coisas simples, tudo o que você precisa fazer é gerar um valor de verdade ou falsey, dependendo se uma determinada série de comandos venceria ou não um determinado jogo (sem interatividade, sem resultados amigáveis ao ser humano, etc.)
Regras do jogo
- O mundo é sempre composto por um corredor com 10 salas conectadas. Cada quarto requer uma chave para entrar, mas pode ser fechado a qualquer momento sem uma chave (por isso acho que é algum tipo de trava);
- O jogador começa na sala 0 e ganha se entrar na sala 9 (quando chegar à sala 9, poderá fazer o que quiser, incluindo ir para outra sala e ainda terá vencido);
- Cada quarto pode conter qualquer número de itens;
- Existem até 26 itens, chamados AZ, e nenhum item aparecerá mais de uma vez no mundo;
- O jogador pode pegar itens da sala atual e colocá-los em seu inventário (eles também podem soltar itens de seu inventário na sala atual);
- O tamanho máximo do inventário do jogador é finito e será fornecido com os detalhes do nível;
- No início do jogo, o inventário do jogador está sempre vazio;
- Não há limite para o número máximo de itens em uma sala (embora o limite implícito seja 26, pois esse é o número total de itens);
- Os itens AJ são teclas que podem ser usadas para entrar nas salas de 0 a 9 (ou seja, o jogador pode passar para a sala 0 se tiver o item A, para a sala 1 se tiver B, etc. observe que as chaves não são necessárias para sair da sala, e o jogador começa na sala 0, então a tecla "A" é necessária apenas se o jogador quiser retornar à sala 0);
- Os itens no inventário do jogador podem ser combinados para criar novos itens (que serão criados no inventário do jogador) - as combinações permitidas serão fornecidas com os detalhes do nível;
- A combinação de itens consome os itens originais (ou seja, se um dos itens era uma chave, não será mais possível usá-la);
- Se o jogador tentar fazer algo impossível (por exemplo, pegar um item que não esteja na sala atual / largar um item que não possui / combinar itens que não possuem / ir para uma sala que não possui a chave para), nada acontece e eles podem continuar;
- O jogador nunca dará um comando sem sentido (por exemplo, vá para a sala 11).
Portanto, um jogo simples pode ser assim:
v
+---+---+---+---+---+---+---+---+---+---+
| C | | J | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| CORRIDOR |
+---------------------------------------+
Inventory capacity: 99
A sala 0 contém o item "C" (que é a chave da sala 2). A sala 2 contém o item "J" (que é a chave da sala 9). O jogador pode ganhar o jogo pegando C, passando para a sala 2, pegando J e depois para a sala 9.
Um jogo mais complexo pode ser:
v
+---+---+---+---+---+---+---+---+---+---+
| C | | X |YZ | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| CORRIDOR |
+---------------------------------------+
Inventory capacity: 10
C+X => D
Y+Z => J
Agora o jogador pode ganhar ao pegar C, passar para a sala 2, pegar X, combinar C com X para criar D e depois passar para a sala 3. Agora eles podem pegar e combinar Y e Z para obter J, permitindo que eles vá para a sala 9.
Formato de entrada
Há um pouco de entrada para lidar, e essa é uma tarefa bastante chata, portanto o formato da entrada é muito flexível. Você obterá os seguintes dados, e como eles devem ser enviados ao seu programa depende muito de você:
- O conteúdo inicial de cada sala (lista de 0 ou mais itens para cada sala);
- Uma coleção de combinações de itens permitidas (cada uma contém 2 itens de entrada e seu item de saída - observe que os itens de entrada não são ordenados);
- O tamanho máximo do inventário (número inteiro, 0 <= tamanho <= 26);
- A lista de comandos que o jogador tentou.
Os comandos do jogador podem ser:
[P]ick up <item>
- pega um item da sala e o coloca no inventário do jogador (se houver espaço)[D]rop <item>
- coloca um item do inventário do jogador na sala atual[C]ombine <item1> <item2>
- combina 2 itens no inventário do jogador para produzir um novo item[G]o to <room>
- viaja para a sala escolhida se o jogador tiver a chave necessária
Por exemplo, o formato de entrada que usei para testar eram argumentos simples do programa:
./adventure YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ G9
# r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 combinations inv. size commands...
# means:
# room 0 starts with items Y & Z, all other rooms start empty
# 1 combination is possible: Y+Z => J
# max inventory size is 2
# player commands are [P]ick up Y, [P]ick up Z, [C]ombine Y and Z, [G]o to room 9
# (in this example, the player wins)
Mas se algum outro formato facilitar, tudo bem (por exemplo, caracteres delimitadores especiais / várias linhas / pedidos diferentes / serializados para JSON / etc.)
Formato de saída
Seu programa deve retornar alguma saída verdadeira se os comandos do jogador fizerem com que eles ganhem o jogo, e alguma saída falsey de outra forma. Essa pode ser uma mensagem reconhecível para stdout, um código de retorno do programa ou qualquer que seja o idioma de sua escolha. Todas as outras saídas serão ignoradas.
Casos de teste
O script bash a seguir fornece um equipamento de teste que verifica a maioria das situações. Ele foi escrito para usar o formato descrito acima, mas modificá-lo para usar um formato diferente é apenas o caso de adicionar uma conversão na invoke
função.
#!/bin/sh
PROG="$1";
if [[ -z "$PROG" ]]; then
echo "Usage: $0 <program-to-test>";
exit 1;
fi;
function invoke {
"$PROG" "$@"
}
RED="\033[1;31m";
GREEN="\033[1;32m";
RESET="\033[m";
FAILURES="0";
function pass {
if ! invoke "$@" >/dev/null 2>&1; then
echo "${RED}Expected pass, got fail:${RESET} $*" >&2;
(( FAILURES = "$FAILURES" + 1 ));
invoke "$@" 2>&1;
fi;
}
function fail {
if invoke "$@" >/dev/null 2>&1; then
echo "${RED}Expected fail, got pass:${RESET} $*" >&2;
(( FAILURES = "$FAILURES" + 1 ));
invoke "$@" 2>&1;
fi;
}
echo "Running tests...";
# R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 C I Cmd...
pass J '' '' '' '' '' '' '' '' '' 0 9 PJ G9;
fail '' J '' '' '' '' '' '' '' '' 0 9 PJ G9;
pass J '' '' '' '' '' '' '' '' '' 0 9 PJ PJ G9;
fail J '' '' '' '' '' '' '' '' '' 0 9 PJ;
fail J '' '' '' '' '' '' '' '' '' 0 9 G9;
pass J '' '' '' '' '' '' '' '' '' 0 9 G9 PJ G9;
pass J '' '' '' '' '' '' '' '' '' 0 1 PJ G9;
fail J '' '' '' '' '' '' '' '' '' 0 0 PJ G9;
fail J '' '' '' '' '' '' '' '' '' 0 9 PJ DJ G9;
fail J '' '' '' '' '' '' '' '' '' 0 9 PJ PJ DJ G9;
pass J '' '' '' '' '' '' '' '' '' 0 9 PJ DJ PJ G9;
pass J '' '' '' '' '' '' '' '' '' 0 9 PJ DJ PJ G9;
pass B CJ '' '' '' '' '' '' '' '' 0 2 PB G1 DB PC PJ G9;
fail B CJ '' '' '' '' '' '' '' '' 0 2 PB G1 DB PB PC PJ G9;
pass AJ '' '' '' '' '' '' '' '' '' 0 2 PA PJ G9;
pass B D '' J '' '' '' '' '' '' 0 2 PB G1 PD G3 DB PJ G9;
fail B D '' J '' '' '' '' '' '' 0 2 PB G1 PD G2 DB PJ G9;
fail B D '' J '' '' '' '' '' '' 0 2 PB G1 PD G3 PJ G9;
fail B D J C '' '' '' '' '' '' 0 2 PB G1 PD G3 PJ G9;
pass AJ '' '' '' '' '' '' '' '' '' 0 2 PA PJ G9 G0;
fail ADJ '' '' '' '' '' '' '' '' '' 0 3 PA PD PJ G3 DJ G0 PJ G9;
pass ADJ '' '' '' '' '' '' '' '' '' 0 3 PA PD PJ G3 DJ G0 G3 PJ G9;
fail ADJ '' '' '' '' '' '' '' '' '' 0 3 PA PD PJ G3 DJ G0 DD G3 PJ G9;
pass ADJ '' '' '' '' '' '' '' '' '' 0 3 PA PD PJ DD G3 DJ G0 DD G3 PJ G9;
fail ADJ '' '' '' '' '' '' '' '' '' 0 1 PA DA DA PD PJ G9;
pass ADJ '' '' '' '' '' '' '' '' '' 0 1 PA DA DA PJ G9;
fail ABCDEFGHIKLMNOPQRSTUVWXYZ J '' '' '' '' '' '' '' '' 0 26 PA PB PC PD PE PF PG PH PI PJ PK PL PM PN PO PP PQ PR PS PT PU PV PW PX PY PZ G9;
pass ABCDEFGHIJKLMNOPQRSTUVWXYZ '' '' '' '' '' '' '' '' '' 0 26 PA PB PC PD PE PF PG PH PI PJ PK PL PM PN PO PP PQ PR PS PT PU PV PW PX PY PZ G9;
fail YZJ '' '' '' '' '' '' '' '' '' 0 2 PY PZ CYZ PJ G9;
pass YZJ '' '' '' '' '' '' '' '' '' 1 YZW 2 PY PZ CYZ PJ G9;
pass YZJ '' '' '' '' '' '' '' '' '' 1 YZW 2 PY PZ CYZ PJ CWJ G9;
fail XYZJ '' '' '' '' '' '' '' '' '' 1 YZW 2 PY PZ CYZ PX PJ G9;
fail XYZJ '' '' '' '' '' '' '' '' '' 1 YZW 2 PY PZ CYZ PX DY DZ PJ G9;
pass XYZJ '' '' '' '' '' '' '' '' '' 1 YZW 2 PY PZ CYZ PX DW PJ G9;
pass YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 CYZ G9;
pass YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ DJ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ DJ PY PZ CYZ G9;
fail WZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PW PZ CYZ G9;
fail WZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CYZ G9;
pass YZ '' '' '' '' '' '' '' '' '' 1 YZJ 2 PY PZ CZY G9;
pass YZ '' '' '' '' '' '' '' '' '' 1 ZYJ 2 PY PZ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 1 PY PZ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 1 PY PZ CYZ PY PZ CYZ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 1 PY PZ CYZ PJ G9;
fail YZ '' '' '' '' '' '' '' '' '' 1 YZJ 1 PJ G9;
pass BW UV '' '' '' '' '' '' '' '' 3 BUR WVS RSJ 2 PB PW G1 DW PU CBU DR PW PV CVW PR CRS G9;
fail BW AUV '' '' '' '' '' '' '' '' 3 BUR WVS RSJ 2 PB G1 PU CBU DR PA PB G0 DA PW G1 PV CVW PR CRS G9;
pass BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PC PA PB G0 DA PW G1 DB PV CVW PR CRS G9;
fail BCW UV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PC PA PB G0 DA PW G1 DB PV CVW PR CRS G9;
fail BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU PA PB G0 DA PW G1 DB PV CVW PR CRS G9;
fail BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PA G0 DA PW G1 DB PV CVW PR CRS G9;
fail BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PB G0 DA PW G1 DB PV CVW PR CRS G9;
fail BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PA PB G0 DA G1 DB PV CVW PR CRS G9;
fail BCW AUV '' '' '' '' '' '' '' '' 3 CUR WVS RSJ 2 PB PC G1 DB PU CCU DR PA PB G0 DA PW G1 DB CVW PR CRS G9;
pass BFK LG M N O CDE PQR U W '' 10 BPT CQS TSH HUI IWV VFA GRX MXZ ANY YZJ 5 \
PB PF PK G1 PL PG G6 DB DK DL G5 PC PD PE G6 DF G2 PM G6 DM DC G3 PN G4 PO G6 DN DO DD DE \
PB PP CBP PC PQ CCQ CTS G7 PU CUH G8 PW CWI G6 PF CVF PR PM PN CGR CMX CAN CYZ G9
fail BFK LG M N O CDE PQR U W '' 10 BPT CQS TSH HUI IWV VFA GRX MXZ ANY YZJ 5 \
PB PF PK G1 PL PG G6 DB DK DL G5 PC PD PE G6 DF G6 DM DC G3 PN G4 PO PM G6 DN DO DD DE \
PB PP CBP PC PQ CCQ CTS G7 PU CUH G8 PW CWI G6 PF CVF PR PM PN CGR CMX CAN CYZ G9
if (( "$FAILURES" == "0" )); then
echo "${GREEN}All tests passed${RESET}";
else
echo "${RED}Total failures: $FAILURES${RESET}";
fi;
Ganhando
Código padrão golf: o código mais curto (em bytes) vence. As inscrições devem seguir as regras do jogo, o que, na prática, significa que devem passar em todos os casos de teste (mais testes podem ser adicionados, se necessário).