Escolar Documentos
Profissional Documentos
Cultura Documentos
Observe que ao listar as casas de um tabuleiro, podemos enumerá-las da esquerda para a direita
e de cima para baixo. A cada casa corresponde um ı́ndice na sequência, que vem a ser chamado
de ı́ndice da casa. No tabuleiro 3 × 3 abaixo cada casa do tabuleiro contém como número o seu
próprio ı́ndice:
0 1 2
3 4 5
6 7 8
1
é respectivamente 1, 3, . . . , 2n2 − 3, para i = 1, . . . , n2 − 1; sendo que os pares de ı́ndices de
diferença 1 cujas casas não são vizinhas são aqueles em que a soma dos ı́ndices mais 1 tem resto
2n − 1 ao ser dividida por 2n. Em suma,
• Duas casas de um tabuleiro são vizinhas na vertical se seus ı́ndices possuem diferença n;
• Duas casas de um tabuleiro são vizinhas na horizontal se seus ı́ndices possuem diferença
1 e sua soma não deixa resto 2n − 1 ao ser dividida por 2n.
Tomemos agora um exemplo mais complexo em que n = 3. Temos 9 valores possı́veis nas
9 casas de um tabuleiro válido. Usando o mesmo esquema de codificação como o do EP1, o
inteiro com representação decimal
6053444 = 8 × 90 + 7 × 91 + 6 × 92 + 5 × 93 + 4 × 94 + 3 × 95 + 2 × 96 + 1 × 97 + 0 × 98
8 7 6
5 4 3
2 1 0
8 7 6
5 4 3
2 0 1
Observe que: os dois tabuleiros diferem apenas nas casas de ı́ndices 7 e 8, as duas últimas; que
elas são vizinhas, na horizontal; e que a diferença entre estes ı́ndices é 1 e sua soma é 15, que
deixa resto 3 ao ser dividida por 6.
Assim sendo, os dois tabuleiros codificados pelos inteiros 6053444 e 44317196 constituem um
movimento válido, o primeiro movimento da sequência de tabuleiros
Esta é uma sequência de 37 tabuleiros válidos, cujos 36 movimentos são todos válidos, e que
permutam as casas do tabuleiro inicial 6053444 para o tabuleiro final 42374116, denotado
0876543219 e impresso
1 2 3
4 5 6
7 8 0
2
Uma sequência de tabuleiros cujos movimentos são todos válidos possui os tabuleiros todos
válidos e é dita uma sequência de tabuleiros coerente. Se além disso ela permuta as casas do
tabuleiro inicial para o tabuleiro final
1 2 ··· n − 1 n
n+1 n+2 · · · 2n − 1 2n
.. .. .. ..
. . . .
2 2 2
n − n + 1 n − n + 2 · · · n − 1 0,
***
Deverão ser completados os corpos das funções no código fornecido ao abrir o VPL. O nome
das funções e sua lista de parâmetros não devem ser alterados.
Pede-se que sejam entregues:
Para n igual a 3 e tabuleiro igual a 300585916, deve ser impresso (a menos da margem
em branco):
tabuleiro 300585916 :
1 2 3
0 4 5
7 8 6
tabuleiro 931611432777499425 :
1 2 3 4
5 6 7 8
9 10 15 11
13 14 12 0
tabuleiro 0 :
0 0
0 0
3
• A função tabuleiro_valido que verifica se o um inteiro tabuleiro codifica um tabuleiro
válido com n2 casas com inteiros de 0 a (n2 –1), cada qual aparecendo uma única vez, e
definida a partir da linha de código:
A função não lê nem imprime nada, apenas devolve o valor True ou False conforme seja
verdade que o tabuleiro seja válido ou não.
e que devolve o ı́ndice x da permutação permut que contém y. A lista permut é uma per-
mutação de todos os inteiros de 0 a len(permut)-1 Ex: indice([2,3,1,0],3) devolve
1 e indice([2,3,1,0],2) devolve 0.
e que devolve True se as casas de ı́ndices indice1 e indice2 em tabuleiros n por n forem
vizinhas, ou False caso contrário. Assim, as chamadas casas vizinhas( 5, 8, 3) e
casas vizinhas( 5, 4, 3) devolvem True e as chamadas casas vizinhas( 5, 6, 3)
e casas vizinhas( 5, 1, 3) devolvem False.
4
e que verifica se os dois tabuleiros fornecidos — tabuleiro1 e tabuleiro2, ambos n por
n — constituem um movimento válido ou não. Assim, a chamada movimento_valido(
6053444, 44317196, 3) devolve True e as chamadas movimento_valido( 6053444,
63422828, 3) e movimento valido( 57, 45, 2 ) devolvem False. O código fonte de
sua função deve chamar a função sequencia de digitos e casas vizinhas.
e que devolve o código do novo tabuleiro obtido ao mover, no tabuleiro válido n por
n, a casa especificada pelo numero a mover para a casa livre vizinha. Devolve -1 se
as duas casas envolvidas não são vizinhas. Assim, move numero( 6053444, 1, 3 ) de-
volve 44317196 e move numero( 6053444, 4, 3 ) devolve -1. O código fonte de sua
função será bastante simplificado se você chamar as funções sequencia de digitos,
casas vizinhas, numero e indice.
e que propicia que o jogador possa percorrer uma sequência de tabuleiros vencedora.
Dados um tabuleiro válido inicial e um tabuleiro válido final, ambos n por n, a função
jogo( inicial, final, n) parte do tabuleiro inicial e permite que o jogador tente
percorrer uma sequência de tabuleiros coerente até o tabuleiro final. A cada rodada ela
pede que ele
5
e efetua a mudança de casas, obtendo um novo tabuleiro após a troca e exibindo-o com
a função imprime_tabuleiro. Novas rodadas são jogadas até que o tabuleiro final seja
atingido ou o jogador escolha algum movimento inválido através de uma casa que não
seja vizinha à casa livre. No primeiro caso, a mensagem "Tabuleiro final atingido!"
é impressa, bem como a sequência de tabuleiros vencedora (vide exemplo de execução a
seguir). No segundo caso, é exibida a mensagem "Número n~ ao está em casa vizinha à
casa livre!". A função devolve True caso o tabuleiro final seja atingido e False caso
contrário. A sequência vencedora de 37 tabuleiros vista anteriormente pode ser obtida
pelo jogador depois de executar jogo(6053444,42374116,3) ao digitar a sequência de
36 números 1, 4, 3, 1, 4, 2, 5, 8, 7, 6, 1, 3, 6, 1, 3, 6, 2, 5, 8, 2, 6, 4, 5, 6, 2, 7, 1, 2,
4, 5, 6, 8, 7, 4, 5, 6. Recomenda-se que o código fonte de sua função chame as funções
imprime tabuleiro, sequencia de digitos, casas vizinhas, numero e indice. Vemos
a seguir uma execução da chamada jogo(30,57,2) que a sua implementação deve ser
capaz de reproduzir:
Convém notar que nem sempre existe uma sequência vencedora que leve do tabuleiro
inicial ao final, como se pode verificar no caso do tabuleiro 2x2 de código 27. A seguir
temos uma execução de jogo(27,57,2):
6
tabuleiro 147 :
3 0
1 2
Digite o número da casa a trocar com a casa livre: 3
tabuleiro 156 :
0 3
1 2
Digite o número da casa a trocar com a casa livre: 1
tabuleiro 141 :
1 3
0 2
Digite o número da casa a trocar com a casa livre: 2
tabuleiro 45 :
1 3
2 0
Digite o número da casa a trocar com a casa livre: 3
tabuleiro 225 :
1 0
2 3
Digite o número da casa a trocar com a casa livre: 1
tabuleiro 228 :
0 1
2 3
Digite o número da casa a trocar com a casa livre: 2
tabuleiro 198 :
2 1
0 3
Digite o número da casa a trocar com a casa livre: 3
tabuleiro 54 :
2 1
3 0
Digite o número da casa a trocar com a casa livre: 1
tabuleiro 114 :
2 0
3 1
Digite o número da casa a trocar com a casa livre: 2
tabuleiro 120 :
0 2
3 1
Digite o número da casa a trocar com a casa livre: 3
tabuleiro 75 :
3 2
0 1
Digite o número da casa a trocar com a casa livre: 1
tabuleiro 27 :
3 2
1 0
7
Digite o número da casa a trocar com a casa livre: 0
Número n~
ao está em casa vizinha à casa livre!
Sequ^encia coerente de 13 tabuleiros:
27 147 156 141 45 225 228 198 54 114 120 75 27
• A função main que executa o programa principal. Esta função oferece ao jogador um menu
de opções de jogo que direta ou indiretamente utiliza as funções acima. Observe que o
código fonte fornecido a seguir chama respectivamente as funções imprime sequencia,
numero, tabuleiro valido, movimento valido, sequencia coerente, move numero e
jogo nas opções de 1 a 7.
def main():
n = int( input( "Digite o valor de n: " ) )
base = n * n
m = []
for i in range(n*n):
m.append(i+1)
m[n*n-1] = 0
final = numero( m, base )
8
if tabuleiro_valido( tab, n ):
print( "é válido" )
else:
print( "n~ao é válido" )
elif opcao==4:
tab1 = int( input( "Digite o código do primeiro tabuleiro: " ) )
tab2 = int( input( "Digite o código do segundo tabuleiro: " ) )
print( "O movimento do tabuleiro", tab1,
"para o tabuleiro", tab2, end=" " )
if movimento_valido(tab1, tab2, n):
print( "é válido" )
else:
print( "n~ao é válido" )
elif opcao==5:
print( "Digite uma sequ^ encia n~ ao vazia de tabuleiros",
"terminada por 0" )
t = int( input( "Digite o código do primeiro tabuleiro: " ) )
sequencia = []
while t != 0:
sequencia.append( t )
t = int( input( "Digite o código do tabuleiro seguinte" +
" ou 0 para terminar: " ) )
print( "A sequ^ encia digitada possui", len(sequencia),
"elementos e ", end="" )
if sequencia_coerente( sequencia, n ):
print( "é coerente" )
else:
print( "n~ao é coerente" )
elif opcao==6:
tab1 = int( input( "Digite o código do tabuleiro: " ) )
if tabuleiro_valido( tab1, n ):
numero_a_mover = int( input (
"Digite o número da casa a trocar com a casa livre: ") )
tab2 = move_numero( tab1, numero_a_mover, n )
if tab2 != -1:
print( "O tabuleiro após a troca tem código",
tab2, "e é impresso" )
imprime_tabuleiro( tab2, n)
else:
print( "Número n~ ao está em casa vizinha à casa livre!" )
else:
print( "O tabuleiro n~ ao é válido")
elif opcao==7:
tab = int( input( "Digite o código do tabuleiro inicial: " ) )
if tabuleiro_valido( tab, n ):
jogo( tab, final, n)
else:
9
print( "Tabuleiro inicial inválido")
print( "0: término; 1: impress~
ao; 2: leitura; 3: tabuleiro;" )
opcao = int( input(
"4: movimento; 5: sequ^encia; 6: número; 7: jogo. Opç~
ao: " ) )
print( "Término do programa" )
Para efeito da correção do EP2 no VPL, a função principal main() fornecida, bem como
a sua chamada (exibida abaixo), não devem ser alteradas. O propósito do comando
condicional abaixo será explicado em aula em um momento oportuno. Sem o seu uso, o
corretor do VPL não irá funcionar adequadamente.
if __name__ == "__main__":
main()
Neste EP, você deve usar os recursos da linguagem vistos até a semana 7 (listas). Em
particular, não é permitido o uso de:
• matrizes, mesmo que sejam abordadas em sala antes do prazo de entrega deste EP;
• manipulação de string além do que já tiver sido visto até a semana 7;
• métodos ou funções nativas associados à classe das listas que não foram abordados.
10