Tic-Tac-latino!
Esta é uma história verdadeira, então os nomes foram alterados.
Meu professor de latim, Sr. Latin, criou sua própria variante proprietária (sem brincadeira). Vamos chamar de tic-tac-latin. O jogo é simples, é essencialmente tic tac toe jogado em uma grade de quatro por quatro.
Declaração formal de regra
Uma linha é uma linha, coluna ou uma diagonal. Existem dois símbolos, 'X' e 'O', mas um ou ambos podem ser substituídos por um símbolo diferente.
Você marca um ponto quando possui três do seu símbolo e um do outro personagem.
Estes arranjos pontuam:
--- O -O-- XXXO XOOX O -XX - O - - X - --- O
Estes não pontuam:
---- XXXX ---- OOOO ---- XXX- ---- OOO-
O jogo é ganho sempre que um jogador tem mais pontos que outro. O jogo é empatado apenas se o tabuleiro estiver cheio.
Desafio
Resolva este jogo. Seu trabalho é fornecer uma maneira de garantir uma vitória ou empate, o que for o resultado ideal.
Sua solução pode optar por iniciar primeiro ou segundo (e, portanto, pode escolher seu símbolo). Não é obrigatório implementar um jogo interativo em que as entradas do usuário se movam e a exibição correspondente seja alterada. Também pode ser uma função ou programa que recebe a entrada como um estado do jogo e gera um novo tabuleiro ou uma descrição de sua jogada . Qualquer uma das opções deve ser executada em aproximadamente dez segundos por movimento realizado.
Jogar seu jogador contra qualquer sequência de movimentos deve dar o resultado ideal. Isso significa que você pode assumir que a posição de entrada é aquela que pode ser alcançada com o player. Os envios devem ser determinísticos e não precisam necessariamente fornecer uma prova de otimização, mas se forem quebrados (por serem derrotados), seus envios serão considerados inválidos (você pode deixar para lá, mas adicionar (quebrado) no título).
Essa é uma tarefa não trivial, portanto, qualquer envio válido é impressionante e merece um visto aceito, mas tornarei o código de golfe o principal critério de vitória.
O vencedor é escolhido descendo esta lista até que um vencedor seja escolhido.
- Implementação resolvida mais curta que sempre vence
- Implementação mais curta
Respostas:
Perl, 147 bytes (não concorrente, leva mais de 10 segundos por movimento)
Inclui +4 para
-0p
O programa é reproduzido
X
. Jogará um jogo perfeito.Insira a placa no STDIN, por exemplo:
A saída será a mesma placa, com todas
X
substituídas porO
e vice-versa. As vagas vazias serão preenchidas com um número indicando o resultado se X for jogado lá, o que1
significa que o resultado será uma vitória,2
um empate e3
uma perda. Um jogo terminado retorna a mesma posição com as cores invertidas.Neste exemplo, a saída seria:
Portanto, a posição é uma vitória,
X
se ele jogar nos 3 lugares ao longo do topo e da esquerda. Todos os outros movimentos perdem.Essa saída confusa é realmente conveniente se você quiser saber como o jogo continua após uma jogada. Como o programa sempre é reproduzido,
X
você deve trocarX
eO
ver os movimentosO
. Aqui, por exemplo, é bem claro queX
ganha ao jogar no canto superior esquerdo, mas e seX
jogar na terceira posição ao longo do topo? Basta copiar a saída, colocar umO
lugar no movimento que você selecionar e substituir todos os outros números-
novamente, então aqui:Resultando em:
Obviamente, todo movimento
O
deve perder, então como ele perde se jogar no canto superior esquerdo? Novamente, faça isso colocandoO
no canto superior esquerdo e substituindo os dígitos por-
:Dando:
Então X tem apenas um caminho a percorrer para sua vitória:
Dando
A situação para
O
permanece sem esperança. É fácil ver agora que cada movimento permiteX
ganhar imediatamente. Vamos pelo menos tentar fazer 3 O's seguidos:Dando:
X
joga a única jogada vencedora (observe que isso ocorreXXXO
na terceira coluna:Aqui a saída é:
porque o jogo já estava terminado. Você pode ver a vitória na terceira coluna.
O programa atual
tictaclatin.pl
:Aplicado ao tabuleiro vazio, ele avalia 9506699 posições, o que leva 30 GB e 41 minutos no meu computador. O resultado é:
Assim, cada movimento inicial é empatado. Então o jogo é um empate.
O uso extremo da memória é causado principalmente pela recursão em uso
do$0
. O uso desta versão de 154 bytes usando uma função comum precisa de 3Gb e 11 minutos:o que é mais suportável (mas ainda é demais, algo ainda deve estar vazando de memória).
A combinação de várias acelerações leva a esta versão de 160 bytes (5028168 posições, 4 minutos e 800M para o tabuleiro vazio):
Esse último usa
0
para uma vitória (não confundaO
),1
para um empate e2
para uma derrota. A saída deste também é mais confusa. Ele preenche a jogada vencedora para X no caso de uma vitória sem troca de cores, mas se o jogo de entrada já foi ganho, ainda assim a troca de cores e não preenche nenhuma jogada.É claro que todas as versões ficam mais rápidas e usam menos memória à medida que a placa se enche. As versões mais rápidas devem gerar um movimento em menos de 10 segundos assim que 2 ou 3 movimentos forem feitos.
Em princípio, esta versão de 146 bytes também deve funcionar:
mas na minha máquina ele aciona um bug perl e despeja o núcleo.
Todas as versões, em princípio, ainda funcionarão se o cache da posição de 6 bytes feito por
$$_||=
for removido, mas isso usa tanto tempo e memória que funciona apenas para placas quase cheias. Mas, em teoria, pelo menos eu tenho uma solução de 140 bytes.Se você colocar
$\=
(custo: 3 bytes) imediatamente antes do$@<=>0
painel, cada placa de saída será seguida pelo status de todo o painel:1
paraX
vitórias,0
empates e-1
perdas.Aqui está um driver interativo baseado na versão mais rápida mencionada acima. O motorista não tem lógica para quando o jogo terminar, então você deve se parar. O código golfado sabe embora. Se a jogada sugerida retornar sem
-
substituir por nada, o jogo acabou.fonte
$move
é declarado na linha 11. Não tenho idéia se existe uma heurística humana. Este programa apenas faz minimax na árvore do jogo, não possui nenhum conhecimento estratégico.JavaScript (ES6) 392 bytes
Uso
O "bot" tocará em segundo.
Desenhe uma grade 4x4 numerada assim:
Vamos executar isso no console do navegador: basta colocar
f=
antes do códigoEntão, se eu quiser começar
1
, eu correriaf([1])([])
e isso me dará14
.Boa jogada ... E se eu jogar
2
depois?f([2,1])([14])
. Voltará13
.Deixe-me tentar se render. Tocar
3
.f([3,2,1])([14,13])
. Oh0
! Você me pegou!Tocar
0
?f([0,2,1])([14,13])
.15
Ok, vamos continuar jogando ...Nota
Jogue interativamente. Comece com
f([your-step])([])
.Anexe seu próximo passo. (Veja a demonstração acima)
Ajude o "bot" a inserir suas etapas. Não fornecerá bons resultados se você definir aleatoriamente. (Como
f([1,2,4])([14,12])
vai dar14
- Ei, o bot queria jogar na13
segunda jogada!Sumário breve
Enquanto você não se render, o bot fará um movimento de espelho.
Obrigado @EHTproductions por me dizer que eu li mal as regras do jogo e as dicas de golfe: P
Agora também detectará se conseguiu um xeque-mate. Se sim, bloqueie-o!
Suas prioridades: Bloco> Espelho> (fallback) procuram maneiras de reproduzir um espelho
fonte
3,2,1
para você e0
para o bot uma vitória para você?[0,1,2,3].map(i=>{k(n=>n%4==i);k(n=>Math.floor(n/4)==i);})
pode ser jogado no golfe[0,1,2,3].map(i=>k(n=>n%4==i)+k(n=>(n/4|0)==i))
.