O jogo
Nim é um jogo de estratégia matemática, onde 2 jogadores se revezam retirando itens de montes distintos. Por sua vez, você deve pegar pelo menos um item e pode pegar quantos quiser, desde que você pegue apenas um monte. O jogador que pega o último item ganha! Este é um jogo resolvido. Antes de eu entrar na estratégia, você pode tentar jogá-la online aqui .
A estratégia
A estratégia vencedora é explicada com muita clareza e simplicidade aqui neste link. Vou explicar usando termos um pouco mais técnicos. A maneira de ganhar este jogo é sempre levar o máximo de itens possível para que a soma digital-binária seja sempre 0. Considere o seguinte quadro:
*
* *
* * *
* * * *
* * * * *
1 2 3 4 5
Para encontrar a soma digital-binária desta placa, você deve:
Converta o número em cada linha para binário. Portanto, temos 001, 010, 011, 100 e 101.
Adicione todos os números juntos e ignore qualquer transporte.
001 010 011 100 +101 ---- 001
Você também pode bit a bit xor cada número, e isso alcançará o mesmo resultado.
Agora, se a soma nesta configuração atual for 001, então este ainda não é um quadro vencedor. Mas você pode torná-lo um quadro vencedor! Se retirarmos um item das colunas 1, 3 ou 5, a soma será 0. Este é um tabuleiro vencedor, o que significa que, desde que você não cometa um erro, o próximo jogador a perder perderá. Portanto, você deve sempre terminar seu turno com um quadro vencedor. Digamos que você retire um item da coluna 5. Agora o quadro fica assim:
* *
* * *
* * * *
* * * * *
1 2 3 4 5
Contanto que você não estrague tudo, você tem uma vitória garantida. Não há nada que seu oponente possa fazer para impedi-lo. Vamos dizer que ele pega todos os itens da coluna 5.
*
* *
* * *
* * * *
1 2 3 4 5
Onde você iria a seguir? Não role para baixo ainda e tente descobrir por si mesmo.
No momento, a soma é 100. A melhor jogada (e a única jogada vencedora) seria pegar tudo da coluna 4. Isso deixaria o quadro assim:
*
* *
* * *
1 2 3 4 5
e a soma assim
001
010
+011
----
000
isso significa que você está em um tabuleiro vencedor! Yay!
O desafio
Você deve escrever um programa ou função que, dado um quadro nim, retorne uma jogada vencedora ou um valor falsey se não houver uma jogada vencedora.
Sua entrada:
Será o formato de lista nativa do seu idioma, onde cada item da lista corresponde ao número de itens em uma determinada coluna. Por exemplo, a entrada {4, 2, 1, 0, 3} corresponde ao seguinte quadro nim:
* * * * * * * * * * 1, 2, 3, 4, 5
(opcional) O número de linhas. (Para idiomas como C / C ++, onde isso não é conhecido na própria lista.)
Sua saída:
Pode ir para STDOUT ou retornar da função
Deve haver dois números: 1) a coluna da qual estamos removendo (lembre-se de que as colunas são indexadas em 0) e 2) o número de itens a serem removidos dessa linha. Pode ser uma matriz de dois itens, uma sequência de dois números, etc. Lembre-se de que a resposta pode ter mais de 2 dígitos, portanto, retornar a sequência "111" não é válida porque não está claro se isso significa "Remover um item da coluna onze" ou "Remover onze itens da coluna um". "1,11" ou "11,1" seriam ambos aceitáveis.
Se não houver resposta, retorne ou imprima um valor falso. Se o seu idioma puder retornar apenas um tipo de variável (novamente, como C / C ++), um número negativo para a coluna ou 0 ou menos para o número a ser removido serão valores aceitáveis de falsey.
Se o número da coluna ou o número a remover for muito grande, isso será visto como uma saída inválida.
Amostras de entradas / saídas
[1, 2, 3, 4, 5]
---> [0, 1]
ou [4, 1]
ou[2, 1]
[1, 3, 5, 6]
---> [0, 1]
ou [1, 1]
ou[2, 1]
[1, 2, 0, 0, 5]
---> [4, 2]
[1, 2, 3]
---> ERROR
Se você optar por executar uma função em vez do programa completo, deverá escrever um programa completo para demonstrar a função em ação. Isso não conta para a sua pontuação completa. Além disso, espera-se que os programas sejam executados em um período de tempo razoável. Não estou planejando inserir entradas excessivamente grandes; portanto, enquanto seu programa não estiver fazendo uma pesquisa de força bruta por toda a árvore do jogo, você deverá ficar bem.
Como de costume, isso é código-golfe, então as lacunas padrão se aplicam e as respostas são contadas em bytes.
Entre os melhores
Aqui está um snippet de pilha para gerar uma classificação regular e uma visão geral dos vencedores por idioma.
Para garantir que sua resposta seja exibida, inicie-a com um título, usando o seguinte modelo de remarcação:
# Language Name, N bytes
onde N
está o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:
# Ruby, <s>104</s> <s>101</s> 96 bytes
Respostas:
Pitão,
3322212019 bytesVocê pode experimentá-lo no compilador online aqui.
Obrigado a Jakube por remover 12 bytes e Maltysen por remover um byte adicional!
Isso imprime um movimento vencedor da posição atual. Se não houver movimentos vencedores, ele não imprime nada.
Eu usei o algoritmo na wikipedia . Aqui está o detalhamento:
fonte
Pitão, 23 bytes
Experimente online: Demonstração
Isso repete todos os movimentos possíveis e até faz a classificação. Portanto, possui uma complexidade de tempo
O(N*log(N))
e uma memória deO(N)
, ondeN
é a soma da lista de entrada ou o número de itens.Devido à complexidade do tempo ruim, essa pode não ser uma resposta válida. Embora resolva todos os jogos, você pode jogar na vida real com objetos reais instantaneamente.
Explicação:
fonte
CJam,
2120 bytesSalvo um byte em comparação com a versão original, e o tratamento de erros também funciona agora:
Experimente online
A entrada é uma matriz CJam, por exemplo:
Se nenhuma solução for encontrada, ela será impressa
-1 0
, o que atenderá ao meu entendimento dos requisitos de saída.Explicação:
fonte
Ruby, 95
Eu escrevi 2 funções anônimas separadas. A primeira, atribuída
f
no programa abaixo, imprime todas as soluções, e a segundag
(correspondente à pontuação acima, pois é mais curta e mais compatível com a especificação) retorna apenas a solução que requer a remoção do maior número.nos dois casos, a soma dos dígitos é totalizada em
c
. Em seguida, a matriz é repetida e a expressãon=a[i]-(c^a[i])
é usada para calcular o número de contadores a serem removidos (obviamente, isso só pode ser feito se exceder zero).em
f
, todas as soluções possíveis são impressas (sec
for encontrado0
,error
são impressas sem loop.) Fiquei surpreso ao ver que as pilhas diferentes podem exigir a remoção de um número bastante diferente de contadores.na
g
matriz de saídar
é atualizada apenas se o número de contadores a serem removidos exceder o número anterior. a matriz r =[pile index, number to be removed]
é retornada. Se não houver solução, o número de contadores a serem removidos é sempre zero,r
permanece inalterado e o valor inicial de r =[false,0]
é retornado.Economias menores são possíveis se
false
puderem ser alteradas para, por exemplo,"!"
e se alguma solução válida, em vez da maior, puder ser retornada (excluindo&&n>r[1]
.)Formatado no programa de teste
fonte
r[1]
sempre é pelo menos zero, acho que>0&&n>r[1]
pode ser reduzido para>r[1]
Mathematica, 73 bytes
fonte
JavaScript (ES6), 54 bytes
Retorna o par
[column, number]
ou falseExperimente online!
Comentado
fonte