Curso de ScriptVox Intermediário - Aula 8 - Prof. Oswaldo Vernet - iNCE/UFRJ

Continuaremos, nesta oitava aula, a falar de listas na linguagem ScriptVox.

Vamos desenvolver um pequeno jogo utilizando listas. Será um jogo de cartas, no
qual o usuário e o computador são adversários. De início, tiramos os coringas do baralho e
ficamos apenas com as 52 cartas tradicionais, sendo 13 de cada naipe. Cada carta tem um
valor em pontos: o "Ás" vale 1, as cartas numéricas valem tantos pontos quanto o seu
próprio número, o valete vale 11, a dama vale 12 e o rei vale 13. O jogo é simples:
as cartas são embaralhadas no início e dispostas num monte, colocado entre os dois
jogadores. Enquanto o monte de cartas não se esvaziar, os jogadores vão, alternadamente,
retirando a primeira carta do monte e o número de pontos de cada um vai sendo acumulado
de acordo com os valores das cartas que tiraram. Vence quem tiver mais pontos.

Todo problema em computação pode ter sua solução facilitada ou dificultada, dependendo da
maneira que escolhemos para representar as informações no programa. Em nosso caso, precisamos
manipular um baralho de 52 cartas e devemos ser capazes de realizar quatro operações sobre 
este monte de cartas, que enumeramos a seguir: 

1. A primeira operação consiste em embaralhar o monte de cartas, colocando nele as 52
   cartas em uma ordem aleatória. Vamos chamá-la de EMBARALHA MONTE.
   
2. A segunda operação consiste em verificar se o monte de cartas se esvaziou ou se ainda há
   cartas a serem retiradas pelos adversários. Vamos chamá-la de MONTE TEM CARTAS. Logo após
   o embaralhamento, é claro, o monte terá as 52 cartas e não estará vazio. Mas conforme os
   usuários forem tirando cartas, o monte vai diminuindo até esvaziar-se. Precisamos saber
   quando o monte fica vazio porque isto significa o fim do jogo.
   
3. A terceira operação consiste em retirar do monte a carta de cima. Vamos chamá-la de
   COMPRA CARTA. Durante o jogo, os dois adversários vão alternadamente comprando cartas
   e acumulando pontos.

4. A quarta e última operação consiste em, dada uma carta, obter seu valor, ou seja, quantos
   pontos ela vale. Vamos chamá-la de PONTUA CARTA.

O jogo consiste em executar a primeira operação uma vez apenas, só no início, e depois
ficar repetindo as três operações seguintes, na ordem acima, até que o monte de cartas
se esvazie. O cuidado que precisamos ter é na hora de somar os pontos: obtido o valor da
carta, acumulamos uma vez nos pontos do usuário e, na vez seguinte, nos pontos do computador.
Como o usuário é sempre o primeiro a jogar (o computador é gentil), podemos dizer que,
nas vezes ímpares, os pontos obtidos contarão para o usuário e, nas vezes pares, para o
computador.

Vamos criar uma função para implementar cada uma das quatro operações. A função embaralha_monte
não recebe parâmetros e produz o monte de cartas embaralhado. A função monte_tem_cartas retorna 
VERDADEIRO (na verdade, o inteiro um) ou FALSO (na verdade, o inteiro zero), conforme ainda haja
cartas no monte ou não. A função compra_carta simplesmente retira a primeira carta do monte,
retornando a carta que foi retirada. Finalmente, a função pontua_carta retorna um número inteiro, 
que é a quantidade de pontos associada à carta recém comprada.

Uma primeira versão para o programa principal do jogo poderia ser a seguinte:

vez := 1
pontos_computador := 0
pontos_usuário := 0
embaralha_monte ()
enquanto monte_tem_cartas ()
	carta := compra_carta ()
	pontos := pontua_carta ()
	se vez = 0 
		pontos_computador := pontos_computador + pontos
		escreve "Seu adversário comprou a carta " carta " e acumulou " pontos_computador " pontos até agora"
	senão
		pontos_usuário := pontos_usuário + pontos
		escreve "Você comprou a carta " carta " e acumulou " pontos_usuário " pontos até agora"
	fim se
	vez := 1 - vez
fim enquanto

Observe como controlamos se é a vez do computador ou a vez do usuário. A variável "vez" é
inicializada com o valor 1, significando que é vez do usuário. A última linha do bloco
do comando ENQUANTO contém a seguinte atribuição:

vez := 1 - vez

Esta atribuição tem o seguinte efeito: quando "vez" vale 1, a expressão um menos vez dá zero e,
na próxima iteração, "vez" terá o valor zero; quando "vez" vale zero, a expressão um menos
vez dá um e, na próxima iteração, "vez" terá o valor um. Entendeu? O valor da variável "vez"
fica alternando entre 1 (usuário) e 0 (computador).

Um ponto importante deve ser observado antes de prosseguirmos. Por que optamos por criar uma
função para cada uma das quatro operações?  Por que simplesmente não implementamos tudo
no programa principal?

A grande vantagem de criar funções é que, no programa principal, estará programada apenas a 
essência do jogo, chamando as quatro operações da maneira correta e no momento correto.
Assim, o programa principal fica independente de como implementamos as operações. 
Nesta aula, vamos usar listas, mas, em algum momento futuro, podemos mudar de ideia e usar
outro recurso para implementar as operações. Daí, bastará reescrever as quatro funções,
porque o programa principal não precisará ser alterado.

Muito bem. Poderemos partir agora para a implementação, escolhendo um modo de representar
o monte de cartas e escrevendo o código correspondente a cada uma dessas quatro operações.
Já que estamos estudando listas, vamos tentar utilizá-las na nossa solução: o monte de cartas
será, então, uma lista e deverá estar armazenada em alguma variável do script. Que tal
chamá-la de "monte"?

A primeira pergunta é: como embaralhar as cartas? A solução matemática para isto consiste 
em gerar aleatoriamente uma PERMUTAÇÃO das 52 cartas. 

Um método simples para gerar uma permutação das 52 cartas consiste dos cinco passos seguintes: 

Passo 1. Disponha as cartas numa lista auxiliar em alguma ordem conhecida, por exemplo: todas
         as cartas de ouros, do ás ao rei; depois todas as cartas de espadas, todas as cartas 
         de copas e, finalmente, todas as cartas de paus. Sempre do ás ao rei dentro de cada naipe.
Passo 2. O monte de cartas embaralhado será também uma lista, que começará vazia.
Passo 3. Escolha aleatoriamente uma posição válida na lista auxiliar, ou seja, um número inteiro
         compreendido entre zero e o tamanho da lista auxiliar menos um (que corresponde 
		 à última posição).
Passo 4. Retire da lista auxiliar a carta que ocupa a posição escolhida no passo 3.
Passo 5. Anexe ao monte de cartas a carta retirada da lista auxiliar no Passo 4.

Os passos 3, 4 e 5 devem ser repetidos até que acabem as cartas da lista auxiliar. A cada
repetição destes passos, tiramos uma carta da lista auxiliar e anexamos esta carta
ao monte. Portanto, quando a lista auxiliar ficar vazia, o monte de cartas conterá todas 
as 52 cartas em alguma ordem desconhecida pelos usuários e, portanto, estará embaralhado.

Antes de analisar o exercício, certifique-se de que compreendeu bem este algoritmo para gerar
permutações. Na verdade, ele é mais geral do que parece e pode ser aplicado a uma lista qualquer
de objetos, não necessariamente cartas.  


EXERCÍCIO

Exercício de avaliação (enviar para scriptvox@gmail.com até o meio-dia de 13 de fevereiro de 2012)

Neste exercício, você começará a implementar este jogo e, nas próximas aulas, irá completando a 
implementação.

Sua primeira tarefa será, portanto, implementar a função embaralha_monte. Antes disso, releia
o final da aula 7 (pode pular mamãe e filho conversando) para ter certeza de que entendeu 
direitinho as operações sobre uma lista e como elas são implementadas em ScriptVox. 

Para facilitar, cada carta deverá ser representada por uma cadeia formada da seguinte maneira: 
os dígitos que representam o valor numérico da carta seguidos da palavra "de" seguida do nome do naipe.
Assim, um três de copas será representado pela cadeia:

"3 de copas"

Uma dama de espadas seria:

"12 de espadas"

Um ás de paus seria:

"1 de paus"

e assim por diante.

É claro que é feio chamar o "Ás" de um, a dama de "12", etc... Mas depois consertaremos isso.

Na função embaralha_monte, todas as variáveis deverão ser locais, exceto a variável "monte", 
que conterá a lista com as cartas embaralhadas. Esta deverá ser global. A lista auxiliar deverá 
ser inicializada tendo como elementos as 52 cartas na ordem especificada no Passo 1 anteriormente. 
Quando a função terminar, a lista auxiliar estará vazia e a lista "monte" global conterá as 
cartas embaralhadas.

Uma maneira interessante de inicializar a lista auxiliar na ordem especificada no Passo 1 
é utilizar o comando "para", que é uma novidade da versão 6.0 do ScriptVox. Este comando 
implementa o PERCURSO em listas e, de modo semelhante a outros comandos de repetição, 
agrega linhas em um BLOCO. A sintaxe lembra a os comandos ENQUANTO e REPETE:

para variável em lista
* BLOCO do comando "para"
fim para

Especificamos uma variável, que é chamda de ITERADOR, e uma lista, que é chamada de DOMÍNIO. 
A ação do comando é a seguinte: o valor da variável vai assumindo cada um dos elementos da 
lista, respeitando a ordem, ou seja, do primeiro até o último; e, para cada valor, o bloco 
é executado. Assim, no exemplo:

lista := [ "uma", "lista", "pequena" ]
para x em lista
	escreve x
fim para

o valor da variável "x", que é o iterador, será, sucessivamente, as cadeias "uma", "lista" e 
"pequena", que são os três elementos da lista especificada como domínio. Para cada um desses
valores, o bloco a ser executado consiste no comando ESCREVE x. Portanto, serão escritas na
tela, uma por linha, as cadeias "uma", "lista" e "pequena".

O número de vezes que o bloco do comando "para" será repetido é a cardinalidade da lista. 
Se ela for vazia, o bloco não será executado nenhuma vez; se a lista for unitária, 
o bloco será executado uma vez; se ela contiver 100 elementos, o bloco será executado 
100 vezes, e assim por diante.

Usando o comando "para", a lista auxiliar pode, então, ser inicializada da seguinte forma:

	lista_auxiliar := []
	para naipe em [ "ouros", "espadas", "copas", "paus" ]
		para carta em [ 1 .. 13 ]
			lista_auxiliar[] := carta + " de " + naipe
		fim para
	fim para

Observou que existe um comando "para" mais interno, no bloco do comando "para" mais externo?
Como funciona isso? É simples: enquanto a variável "naipe" (que é o iterador do comando "para"
mais externo) contiver o primeiro elemento da lista de naipes, que é "ouros", a variável "carta"
(que é o iterador do comando "para" mais interno) assumirá todos os valores inteiros de um a treze.
Assim, concatenando "carta", "de" e "naipe" teremos os nomes de todas as cartas, de um a treze,
do naipe de "ouros". O mesmo vai acontecer para "espadas", "copas" e "paus".

Você se lembra de uma operação entre conjuntos denominada PRODUTO CARTESIANO?  A ideia era 
pegar cada elemento do primeiro conjunto e combinar com todos os elementos do segundo conjunto, 
formando pares. Conseguimos algo parecido aninhando comandos "para": um produto cartesiano
entre listas.
 
Observou o uso da faixa um ponto ponto treze para especificar a lista contendo os inteiros de 
um a treze?  Ela evita que tenhamos de escrever todos os números de um a treze. Você acha
bobagem, que não dá trabalho nenhum escrever treze números? Então tá: imagine se fosse de um a mil. 

Bem, isto apenas inicializa a lista auxiliar. A geração do "monte" embaralhado fica por sua conta.
Use o comando ENQUANTO, anexando cada carta retirada aleatoriamente da lista auxiliar ao final do monte.
Lembre-se de usar o comando RANDOMIZA e de usar a função RAND para gerar um número que seja uma posição 
válida da lista auxiliar. Para saber se a lista auxiliar ainda contém cartas, compare-a com a
lista vazia, no teste do comando ENQUANTO. Assim:

enquanto lista_auxiliar <> []
* bloco do comando ENQUANTO
fim enquanto

Para testar a sua função embaralha_monte, escreva um programa principal que chama a função e depois
escreve o conteúdo da variável "monte", que deverá conter a lista de 52 cartas embaralhada. 

Bom estudo!

Oswaldo Vernet







