SOP-2010-2-sobral

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
A versão imprimível não é mais suportada e pode ter erros de renderização. Atualize os favoritos do seu navegador e use a função de impressão padrão do navegador.

Sistemas Operacionais e Introdução à Programação - 2010-2

Informações gerais

Professor: Marcelo Maia Sobral
Email: msobral@gmail.com
Skype: mm-sobral
Lista de email (forum): sop-ifsc@googlegroups.com
Atendimento paralelo: 2a feira 10h - 11 h, 3a feira 10h - 12 h ou 16h - 17 h, 5a feira 16h - 17h (no Laboratório de Desenvolvimento de Tele)
Reavaliação (recuperação): no final do semestre

Softwares

Será usado como plataforma de estudo o sistema operacional Ubuntu Linux 10.04 LTS. Para obtê-lo há essas opções:

  1. Trazer um CD-R virgem para que eu faça a cópia aqui no IFSC
  2. Fazer o download por conta própria (aprox. 700 MB)
  3. Usar uma máquina virtual do VirtualBox já preparada por mim (menos recomendado, pois o Linux roda mais lento)
    • Trazer um DVD-R ou pendrive com ao menos 4 GB livres.
    • Instalar o VirtualBox em seu computador para executar a máquina virtual

ATENÇÃO: é muito importante que se providencie o quanto antes a instalação do Ubuntu em seu computador. Sem ele você não poderá fazer os exercícios sugeridos, o que atrapalhará seu aproveitamento na disciplina ! O bom andamento do estudo depende muito de não deixar acumular o conteúdo e os exercícios. Acostume a criar uma rotina de estudo, procurando resolver os problemas apresentados e procurando o professor (ou contatando-o por email) para tirar dúvidas.

Listas de exercícios

Referências adicionais

Sistemas operacionais

27/07: Apresentação

Apresentação da disciplina: plano de ensino, avaliação, abordagem pedagógica.

02/08: Introdução a sistemas computacionais

  • Sistemas computacionais (resumo):
    • Visão geral de sistemas operacionais
    • Histórico de sistemas operacionais

Introdução ao Linux

Uso básico da interface gráfica e de texto. Apostila Gerência de Redes (prof. Odilson), capítulos 3 a 5, e capítulos 6 e 7 do Guia Foca Linux Iniciante.

Objetivos:

  1. Conhecer o sistema operacional Linux
  2. Usar a interface gráfica
  3. Usar a interface de linha de comando (shell)
  4. Usar comandos básicos para manipulação de arquivos e diretórios
  5. Conhecer a estrutura de diretórios do Linux

Exercício

  1. Partindo do subdiretório /home/aluno/Desktop, e usando somente caminhos (pathnames) relativos, indique a sequência de comandos necessária para visitar sucessivamente os seguintes subdiretórios:
    • /home/aluno
    • /home/visita
    • /home/visita/Documentos
    • /home/visita/public_html/imagens
    • /etc/default
    • /usr/share/docs
    • /usr/share/docs/python/manual/html
    • /usr/lib/browser-plugins
    • /usr/local/etc
    • /usr/local/man/man1
    • /home/aluno
    • /home/aluno/Desktop
  2. Partindo do subdiretório /home/aluno/Desktop, informe a sequência de subdiretórios (indique-os com seus caminhos absolutos) visitados se forem seguidos os seguintes caminhos relativos:
    • ../Imagens/Fotos
    • 2010/07
    • ../../2009
    • ../../../bin
    • ../../manuel/docs
    • ../../../etc/init.d
    • ../rc5.d
    • ../../var/log/apache2
    • ../../tmp
    • ../../lib/modules
    • ../../usr/bin
    • ../lib/X11
    • ../..

Videos ilustrativos

Textos interessantes sobre história dos sistemas operacionais

03/08: Introdução ao Linux (continuação)

  • Uso básico da interface gráfica e de texto.
    • Apostila Gerência de Redes (prof. Odilson), capítulos 3 a 5
    • Capítulos 6 e 7 do Guia Foca Linux Iniciante.

Objetivos:

  1. Conhecer o sistema operacional Linux
  2. Usar a interface de linha de comando (shell)
  3. Usar comandos básicos para manipulação de arquivos e diretórios
  4. Conhecer a estrutura de diretórios do Linux
  5. Usar comandos básicos para visualização e manipulação de processos

Foram vistos programas para manipulação de arquivos:

  • cat: mostra o conteúdo de um arquivo na tela, porém sem paginá-lo.
  • more: mostra de forma paginada o conteúdo de um arquivo na tela.
  • less: mostra de forma paginada o conteúdo de um arquivo na tela, com alguns recursos a mais (possibilita paginar pra cima ou pra baixo)
  • cp: copia um ou mais arquivos
  • mv: move um ou mais arquivos de um subdiretório para outro, ou renomeia um arquivo
  • rm: remove um ou mais arquivos
  • mkdir: cria um subdiretório
  • rmdir: remove um subdiretório

Exercício

  1. Usando a interface gráfica, organize os arquivos contidos aqui. Eles devem ser colocados nos subdiretórios Imagens, Videos e Documentos, de acordo com seus tipos.
  2. Refaça a questão anterior, porém usando a interface de linha de comando (o shell).

Obs: para extrair os arquivos do exercício faça assim:

aluno@DX~$ tar xjf sop.tar.bz2

... e veja que aparecerá um subdiretório sop com todos os arquivos do exercício lá dentro.

09/08: Processos e memória

Visão geral sobre Sistemas Operacionais:

  • O que são ?
  • Para que servem ?

Processos e multiprogramação: uma visão geral sobre programas, processos, ciclos de um processo, multiprogramação e escalonamento. Ver apostila do prof. Odilson, capítulo 3, e capítulo 5 do Guia Foca Linux Iniciante.

Gerência de memória: visão geral sobre o uso de memória no sistema operacional e pelos processos Uso do laboratório para ilustrar conceitos.

Vários utilitários (programas auxiliares) existem para obter informações do sistema operacional sobre processos e memória. Alguns trabalham em modo texto, como:

  • ps: lista os processos existentes
  • pstree: lista os processos existentes mas de forma hierárquica
  • top: lista os processos mais ativos, junto com informações globais sobre uso dos recursos no sistema operacional (memória, processador, memória virtual, quantidade de processos, carga de trabalho)
  • atop: o mesmo que top, mas com maior detalhamento do uso de recursos mantidos pelo sistema operacional
  • mpstat: mostra estatísticas de uso do processador
  • free: mostra o uso de memória
  • vmstat: mostra o uso de memória, discos e processador no último intervalo de tempo.

Existem também utilitários no modo gráfico. Por exemplo, no Ubuntu há o "Monitor do sistema":

Monitor1.png
Para executar o Monitor do Sistema




Monitor2.png Monitor3.png

Telas do monitor do Sistema

10/08: Sistemas de arquivos; redirecionamentos de entrada e saída padrão; pipes

Resolver a 1a lista de exercícios:

Visão geral sobre sistemas de arquivos: definição de arquivo e diretório, formas de armazenamento em media (discos, DVD, ...), segurança (controle de acesso).

Alguns utilitários de uso comum

Esses utilitários são programas úteis para operações do dia-a-dia com arquivos, e serão úteis para ilustrar os conceitos de entrada e saída padrão:

  • cut: divide as linhas dos arquivos em colunas, e mostra colunas específicas
  • grep: mostra linhas de arquivos que contenham determinada palavra ou padrão de caracteres
  • sort: ordena as linhas de um arquivo
  • paste: combina linhas de arquivos
  • wc: conta linhas, palavras e caracteres
  • tail: mostra as últimas linhas de um arquivo
  • head: mostra as primeiras linhas de um arquivo
  • du: mostra a utilização de disco de um determinado arquivo ou diretório

Entrada e saída padrão

Todo processo possui uma saída padrão, que corresponde a um arquivo ou dispositivo onde os dados de saída do processo (ex: mensagens de texto) serão mostrados. E assim como existe uma saída padrão, todo processo possui uma entrada padrão que corresponde ao arquivo ou dispositivo de onde por default são obtidos os dados de entrada.

Sop-redir.png

Redirecionamento de saída padrão

Normalmente a saída padrão de um processo é a tela do terminal, mas ela pode ser redirecionada para um arquivo ou para outro dispositivo. Assim, as mensagens de texto que um processo gera podem ser guardadas em um arquivo para posterior utilização. No exemplo abaixo, a listagem dos processos foi guardada no arquivo processos.txt:

aluno@D1:~$ ps ax > processos.txt
aluno@D1:~$

O redirecionamento de saída padrão se faz com o símbolo > seguido do nome do arquivo. Note que nada aparece na tela, uma vez que a saída se tornou o arquivo processos.txt. Após executar o comando acima, veja o conteúdo de processos.txt:

aluno@D1:~$ less processos.txt
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:03 /sbin/init
    2 ?        S<     0:00 [kthreadd]
    3 ?        S<     0:00 [migration/0]
    4 ?        S<     0:00 [ksoftirqd/0]
    5 ?        S<     0:00 [watchdog/0]
    6 ?        S<     0:00 [migration/1]
    7 ?        S<     0:00 [ksoftirqd/1]
    8 ?        S<     0:00 [watchdog/1]
    9 ?        S<     0:00 [events/0]
   10 ?        S<     0:00 [events/1]
   11 ?        S<     0:00 [khelper]
   12 ?        S<     0:00 [kstop/0]
   13 ?        S<     0:00 [kstop/1]
   14 ?        S<     0:00 [kintegrityd/0]
   15 ?        S<     0:00 [kintegrityd/1]
   16 ?        S<     0:00 [kblockd/0]
   17 ?        S<     0:00 [kblockd/1]
   18 ?        S<     0:00 [kacpid]
   19 ?        S<     0:00 [kacpi_notify]
   20 ?        S<     0:00 [cqueue]
   21 ?        S<     0:00 [ata/0]
   22 ?        S<     0:00 [ata/1]
processos.txt

Como se pode ver, o texto que apareceria na tela foi guardado em processos.txt. Experimente executar novamente o comando ps ax > processos.txt e veja o resultado. O que aconteceu com o arquivo processos.txt ?

Quando se deseja redirecionar a saída de um processo para um arquivo, porém preservando o conteúdo original desse arquivo, deve-se executar o comando da seguinte forma:

aluno@D1:~$ ps ax >> processos.txt
aluno@D1:~$

... quer dizer, em vez de usar > usa-se >>.

Exercícios

  1. Concatene vários arquivos de texto, e usando redirecionamento de saída padrão grave o resultado em um novo arquivo. Dica: para concatenar use o utilitário cat.
  2. Execute o comando ps > ps.txt. Veja o conteúdo do arquivo resultante ps.txt. Execute novamente ps > ps.txt, e veja como ficou o arquivo ps.txt. O que você pode concluir quanto ao redirecionamento de saída para um arquivo já existente ?
  3. Repita o procedimento do ítem 2, porém executando primeiro ps > ps.txt e depois ps >> ps.txt. Qual foi a diferença ?

Redirecionamento de entrada padrão

Normalmente a entrada padrão corresponde ao teclado do terminal, mas pode ser redirecionada para outro arquivo ou dispositivo. No exemplo abaixo, usa-se o programa wc para contar as linhas, palavras e caracteres contidos no arquivo processos.txt:

aluno@D1:~$ ps ax > processos.txt
aluno@D1:~$ wc < processos.txt
 137  810 7807 processos.txt
aluno@D1:~$

No exemplo acima, gravou-se em processos.txt o resultado do comando ps ax' , e depois usou-se wc para contar linhas, palavras e caracteres desse arquivo. O efeito combinado é a contagem de quantos processos existem no sistema nesse momento (representado pelo número de linhas contidas em processos.txt).

Ao contrário do caso da saída padrão, não é tão comum se usar redirecionamento de entrada padrão. No entanto há um recurso adicional provido pelo sistema operacional que explora a combinação de ambas, e que possibilita combinar as funcionalidades de diferentes programas.

Pipes

Em sistemas operacionais Unix, é possível conectar a saída padrão de um processo à entrada padrão de outro processo, e a isto se chama pipe (que pode ser traduzido como duto ou tubo). Com isto, os dados de saída de um processo serão os dados de entrada de outro processo, o que pode ser explorado para realizar diferentes tarefas. Por exemplo, retomando a contagem de processos vista na seção anterior:

aluno@D1:~$ ps ax | wc
 137  810 7807
aluno@D1:~$

O símbolo de pipe é a barra vertical |. Ao se executarem os comandos acima unidos pelo pipe, a listagem de processos gerada pelo ps ax é automaticamente enviada para a entrada padrão do comando wc. O resultado é a contagem de processos existentes no sistema.

Podem-se ligar mais de dois processos usando pipes. Assim, cria-se um encadeamento de processos, em que a saída padrão de um processo alimenta a entrada padrão do próximo processo. Por exemplo, para se contarem os processos do usuário aluno:

aluno@D1:~$ ps aux | grep aluno | wc
     47     568    5195
aluno@D1:~$


16/08: Localização de arquivos

Uma tarefa usual em um sistema operacional é localizar arquivos. Essa procura pode ser baseada no nome ou parte do nome de arquivo, na data de criação ou última modificação, no nome do usuário ou grupo dono, ou outros atributos do arquivo. Pode ser inclusive baseada numa combinação dessas informações. Por exemplo, pode ser necessário procurar todos os arquivos de música ou video, ou então todos os programas (arquivos executáveis) que pertençam ao superusuário (usuário root). Existem programas capazes de fazer tais buscas tanto no ambiente gráfico quanto no modo texto.

As buscas a serem realizadas são:

  1. Arquivos de música
  2. Arquivos de música ou video
  3. Arquivos de texto ou planilha do Openoffice que não tenham sido modificados a 7 dias ou mais
  4. Arquivos executáveis (programas)
  5. Arquivos executáveis pertencentes ao usuário root

Para iniciar, vamos usar programas gráficos para fazer buscas.

Usando o ambiente gráfico

O primeiro programa gráfico a ser usado é o nautilus, o gerenciador de arquivos disponível no Ubuntu Linux. Para usá-lo para fazer buscas selecione a opção de pesquisa:


Pesquisa1.png


No nautilus aparecerá uma caixa de texto onde se deve digitar o nome ou parte do nome dos arquivos a serem procurados.


Pesquisa2.png


Tente fazer as buscas usando esse programa. Há alguma que não pode ser feita ?

Buscas avançadas

Para fazer buscas que combinem outros critérios que não somente o nome do arquivo deve-se usar outro aplicativo, que está acessível pelo Mmenu Locais:

Pesquisa3.png

Esse aplicativo de busca mostra uma tela em que se adicionam ou removem critérios de busca:

Pesquisa4.png

Como resultado, podem-se localizar arquivos e diretórios que atendam diferentes opçõs de localização:

Pesquisa5.png

Modo texto

A procura de arquivos e diretórios pode ser automatizada com o comando find. Por exemplo, para localizar todos os arquivos ou diretórios chamados default, e que estejam abaixo de /etc:

aluno@D1:~$ find /etc -name default -print
/etc/default
/etc/calendar/default
/etc/X11/xinit/xinput.d/default
aluno@D1:~$

Uso do find :

find pathname [opões]

... sendo pathname o diretório abaixo de que se deseja fazer a busca. As opções servem para selecionar arquivos e diretórios durante a busca, e também para executar ações para cada um deles que for encontrado. Algumas opções mais comuns:

  • -name nome: seleciona arquivos ou diretórios cujos nomes sejam nome' . Essa opção aceita wildcards (* e ?)
  • -type tipo: seleciona apenas o tipo' indicado, que pode ser:
    • d: diretório
    • f: arquivo
    • l: link simbólico (ou atalho)
  • -perm modo: seleciona apenas arquivos ou diretórios que possuam as permissões indicadas em modo
  • -size tamanho: seleciona apenas arquivos com tamanho de acordo com o especificado (em bytes)
  • -mtime n: seleciona apenas arquivos ou diretórios modificados a n * 24 horas atrás
  • -atime n: seleciona apenas arquivos ou diretórios acessados a n * 24 horas atrás
  • -user usuario: seleciona apenas arquivos ou diretórios pertencentes a usuario
  • -exec comando \;: executa comando para cada arquivo ou diretório encontrado. Ex:
    • find /tmp -type f -mtime +7 -exec rm -f {} \; : remove todos os arquivos dentro de /tmp que estejam há 7 dias sem serem modificados. A sequência {} é substituída pelo nome do arquivo encontrado.

... e muitas outras (consulte o manual do find).

Atividade

Usando o modo gráfico E o modo texto, faças as seguintes pesquisas por arquivos:

  1. Encontre o arquivo lsusb, que se encontra em algum subdiretório dentro de /usr
  2. Encontre os arquivos dentro de /usr cujos tamanhos sejam maiores que 20 MB
  3. Encontre os subdiretórios lib, que estão dentro de /usr
  4. Localize todos os arquivos executáveis (i.e., os programas) que existem abaixo de /lib
  5. Localize todos os arquivos pertencentes ao usuário aluno e que estejam dentro de /tmp
  6. Localize o arquivo bits.h em toda a árvore de diretório (quer dizer, a partir da raiz, ou /).
  7. Localize todos os arquivos abaixo de /tmp que tenham sido criados (ou modificados) a um dia ou mais.
  8. Localize os arquivos dentro de /tmp que pertençam a seu usuário.
  9. Localize somente os diretórios dentro de /tmp que pertençam a seu usuário.
  10. Localize somente arquivos dentro de /tmp que tenham menos de 1 kB.
  11. Localize somente arquivos dentro de /tmp que tenham mais de 10 kB.
  12. Localize somente arquivos dentro de /tmp que tenham mais de 10 kB e sejam do seu usuário.
  13. Localize somente arquivos dentro de /tmp que tenham mais de 10 kB e não sejam do seu usuário.
  14. Localize os arquivos dentro de /etc que contenham o texto telnet.
    find /etc -type f -exec grep -q telnet {} \; -print
    
  15. Localize os arquivos dentro de /etc que não contenham o texto root.
    find /etc -type f -not -exec grep -q root {} \; -print
    
  16. Localize os arquivos dentro de /etc que contenham o texto telnet, porém não tenham o texto vt nas mesmas linhas que telnet.
  17. Conte quantos arquivos em /etc contêm o texto root.
  18. (Desafio) Em seu diretório home (pasta pessoal) existem alguns arquivos de video obtidos com sua câmera fotográfica, porém você não sabe exatamente onde estão. Além disso, esses videos são codificados na máquina fotográfica com o codec MJPG, que gera arquivos muito grandes. Se forem recodificados para XVID, os tamanhos desses videos serão reduzidos substancialmente (4 vezes ou mais). Sabendo que se pode recodificá-los no modo texto com o programa mencoder (usando-o assim: mencoder -o novo_video.avi -oac mp3lame -ovc xvid -xvidencopts bitrate=1200 arquivo_video), faça a busca e conversão desses videos para XVID.

17/08: Redirecionamentos, pipes, usuários e grupos

Uso de redirecionamentos e pipes. Para entender a utilidade desses recursos, alguns comandos adicionais serão vistos:

  • cut: divide as linhas dos arquivos em colunas, e mostra colunas específicas
  • grep: mostra linhas de arquivos que contenham determinada palavra ou padrão de caracteres
  • sort: ordena as linhas de um arquivo
  • paste: combina linhas de arquivos
  • wc: conta linhas, palavras e caracteres
  • tail: mostra as últimas linhas de um arquivo
  • head: mostra as primeiras linhas de um arquivo
  • du: mostra a utilização de disco de um determinado arquivo ou diretório

Conceitos de usuários e grupos. Comandos relacionados:

  • whoami: mostra quem é o usuário dono do processo atual (que é o shell)
  • users: mostra os usuários logados no sistema
  • who: mostra os usuários logados no msistema, porém com mais informações sobre cada um deles
  • w: mostra o que os usuários logados estão fazendo agora
  • finger: mostra informações sobre um ou mais usuários
  • passwd: muda a senha de um usuário
  • last: mostra o histórico de usuários logados
  • chfn: muda diversas informações de um usuário (aquelas visíveis com finger)
  • groups: grupos a que um usuário pertence

As informações sobre os usuários estão guardadas no arquivo /etc/passwd. Mas podem estar armazenadas também na rede ... As informações sobre os grupos estão guardadas no arquivo /etc/group.

Atividade

  1. Mostre quais os usuários que existem, junto com seus nomes completos (essa informação está no arquivo /etc/passwd)
  2. Repita o item anterior, mas mostrando em ordem alfabética direta e reversa
  3. Repita o ítem anterior, mas mostrando apenas o último usuário em ordem alfabética, e depois o primeiro usuário
  4. Conte quantos usuários têm o nome completo iniciando com a letra 'A'
    # O caractere ^ na frente da palavra faz com o grep a procure somente no início da linha
    cut -d: -f5 /etc/passwd | grep ^A | wc -l
    
  5. Seja um arquivo com o conteúdo abaixo, que contém uma relação de pessoas com alguns dados pessoais (nome, idade, sexo, profissão, residência):
    Joaquim Silva 34 M comerciante Imaruim
    Vanessa Duarte 28 F engenheira Biguaçu
    Manuel Rosa 61 M médico Anitápolis
    Sergio Queiroz 22 M estudante São José
    Diana Marques 37 F advogada Palhoça
    
    1. Ordene-o alfabeticamente pelo nome
    2. Ordene-o numericamente pela idade
      # Imaginando que o arquivo acima se chame dados.txt
      sort -n -k 3 dados.txt
      
      • Desafio: Como se poderia resolver esse problema se os nomes das pessoas tivessem quantidades variáveis de componentes ? Ex:
        Joaquim Koch Silva 34 M comerciante Imaruim
        Vanessa Duarte 28 F engenheira Biguaçu
        Manuel João da Silva Rosa 61 M médico Anitápolis
        Sergio Felipe Queiroz 22 M estudante São José
        Diana Marques 37 F advogada Palhoça
        
        Dica: você poderia modificar as linhas desse arquivo de forma a delimitar claramente onde está a idade de cada pessoa. Se conseguir fazer algo parecido com o mostrado a seguir, o problema seria mais facilmente resolvido:
        Sergio Queiroz: 22 :M estudante São José
        Vanessa Duarte: 28 :F engenheira Biguaçu
        Joaquim Silva: 34 :M comerciante Imaruim
        Diana Marques: 37 :F advogada Palhoça
        Manuel Rosa: 61 :M médico Anitápolis
        
        Veja o programa sed.
    3. Mostre somente os dados das mulheres
    4. Conte quantos homens e quantas mulheres há nesse arquivo
      # Mulheres ...
      grep " F " dados.txt | wc -l 
      
      # Homens ...
      grep " M " dados.txt | wc -l
      

      ... ou ...
      # Mulheres ...
      grep -w F dados.txt | wc -l 
      
      # Homens ...
      grep -w M dados.txt | wc -l
      
    5. Mostre os dados da primeira pessoa, de acordo com a ordem alfabética
    6. Mostre os dados da última pessoa, de acordo com a ordem alfabética
  6. Imagine que seu diretório de trabalho está muito cheio, e você quer identificar que arquivos ou subdiretórios estão ocupando mais espaço. Combine os comandos du e sort para descobrir isto.
  7. Conte quantos processos pertencem ao usuário aluno, e quantos pertencem a root.
  8. Sejam dois arquivos como mostrado abaixo. Combine suas linhas e mostre o resultado em ordem alfabética.
    abacaxi
    laranja
    morango
    manga
    goiaba
    limão
    

    graviola
    kiwi
    maracujá
    coco
    pêssgo
    
  9. Sejam dois arquivos como mostrado abaixo. Combine suas linhas e mostre o resultado em ordem alfabética. Mostre também o resultado em ordem de quantidade.
    abacaxi
    laranja
    morango
    manga
    goiaba
    limão
    

    1 kg
    500 g
    100 g
    2 kg
    1 kg
    300 g
    

23/08: Editores de texto

Ver capítulo 9 da apostila do prof. Odilson.

Os editores a serem vistos servem pra criar e modificar arquivos de texto simples (contêm apenas texto e sem formatação). Esse tipo de arquivo é muito comum para arquivos de programa, manuais rápidos, e documentos escritos em linguagens de formatação de texto, como HTML e XML.

Alguns desses editores:

  • gedit: um editor de texto simples para o ambiente gráfico. Possui recurso para ressaltar palavras e sentenças, chamado syntax highlight, de acordo com o tipo de texto (se programa em linguagem C, C++, Python, PHP, shll script, ou um texto HTML, entre outros).
  • vi: um editor de programas com recursos avançados de edição. Mas usa uma interface textual com comandos que devem ser memorizados ... algo anacrônico, mas funciona. Como motivação para usá-lo, praticamente todo computador com Unix (não somente Linux) vem com esse editor previamente instalado.
  • nano: um outro editor mais simples, também para modo texto e com menos funcionalidades que o vi, porém um pouco mais amigável.

gedit

Para executar o gedit deve-se selecioná-lo no menu de aplicativos:

Gedit.png


Esse editor é bastante simples, porém útil para a edição de perquenos textos e programas. Algumas funções existentes são busca e substituição de palavras e impressão. Outras funcionalidades podem ser adicionadas por plugins.

Gedit2.png

Experimente editar diferentes tipos de arquivos de texto com o gedit:

nano

O editor nano serve para editar arquivos em modo texto. Sua tela apresenta uma área de trabalho, onde aparece o texto, com uma barra de ajuda embaixo. Nessa barra há os comandos que podem ser usados, que devem ser invocados com a combinação da tecla Ctrl e a letra indicada. Para terminá-lo basta teclar Ctrl X, fornecendo o nome do arquivo onde guardar o texto.

Nano.png


vi

O editor vi é bastante simples e muito utilizado por ser encontrado em todas as distribuições Linux. Poderíamos optar por um editor um pouco mais avançado, mas com o inconveniente de encontrarmos uma distribuição/instalação onde não dispuséssemos deste editor. O editor vi não tem como objetivo formatar textos: negritos, indentações, justificação, etc. Na prática o vi é muito usado para editar textos que não necessitam de formatação em nenhum momento, como por exemplo códigos fonte de programas em alguma linguagem de programação, e que não carreguem o texto com caracteres especiais. Assim, esse editor também é chamado de editor de programas.

Dicas do Maykon:

Modos de operação

O editor vi tem três modos de operação distintos: modo insert , modo escape (também chamado de modo comando), modo last line;

  • insert: usado para a digitação do texto. Neste modo o vi funciona como uma máquina de escrever, com a diferença de que você pode retroceder sobre o texto já digitado para corrigir eventuais erros. Cada caracter que for digitado aparecerá na tela exatamente como foi digitado.
  • escape: os caracteres comuns (letras, números e sinais de pontuação) têm um significado especial e quase todos os caracteres funcionam como comandos; portanto, existem muitos comandos. Alguns comandos servem para passar para o modo insert, outros para movimentar o cursor sobre as linhas do texto, alterar trechos do texto, buscar palavras, etc.
  • last line: os comandos são digitados em uma linha especial que aparece no final da tela quando se digita : (dois pontos) no modo escape. Parte dos comandos do modo escape possuem similares no modo last line, como por exemplo os comandos de edição, que veremos mais adiante. Os comandos no modo last line devem ser seguidos por ENTER, contrariamente ao que acontece no modo escape.

Criação e edição de arquivos

Outro guia rápido sobre vi

Para criarmos um arquivo simplesmente digitamos vi seguido do nome do arquivo. Por exemplo:

vi primeiro.arquivo

Após isto será aberto o editor com conteúdo vazio, no modo comando. Para podermos editar qualquer coisa devemos entrar no modo inserção, para isto basta teclarmos <i> (aparecerá -- INSERT -- na base da janela). Em seguida digitamos o texto propriamente dito, usando o teclado normalmente.

Para salvarmos o texto devemos teclar <Esc> (modo comando), <:> (modo last line> e <w> (write). Assim teremos o nosso texto salvo.

Agora vamos a alguns comandos úteis:

  • Copiar algumas linhas do texto: colocamos o cursor no início do texto a ser copiado e, no modo de comando, teclamos <n>+<y>+<y>, onde n é número de linhas que desejamos copiar. Por exemplo se digitarmos <5>+<y>+<y> copiaremos 5 linhas para o buffer.
  • Excluir algumas linhas do texto: colocamos o cursor no início do texto a ser excuído e, no modo de comando, teclamos <n>+<d>+<d>, onde n é número de linhas que desejamos copiar. Por exemplo se digitarmos <3>+<y>+<y> apagaremos 3 linhas do texto mas que serão armazenadas no buffer.
  • Colar o conteúdo do buffer para alguma parte do texto: colocamos o cursor no ponto onde pretendemos inserir o texto e, no modo de comando, teclamos

    (paste) para inserirmos o texto abaixo da linha do cursor e

    para inserir o texto acima da linha do cursor.

  • Encontrar alguma palavra: no modo de comando, teclamos </> <palavra> <Enter>. O vi mostrará a primeira ocorrência da mesma. Para ir para a próxima ocorrência teclamos <n> (next), e para a ocorrência anterior teclamos <p> (previous)
  • Substituir uma palavra por outra: no modo de comando, teclamos <:s/><palavra></><outra><Enter>. Por exemplo se quisermos substituir velha por nova: <:s/><velha></><nova><Enter>, assim teremos a troca da primeira ocorrência de velha por nova. Para substituirmos todas as ocorrências acrescentamos <%> entre <:> e <s> do caso anterior. Exemplo: <:%s/><velha></><nova><Enter>
  • Inserir o conteúdo de um texto externo em nosso texto: no modo de comando, teclamos <:r>+<caminho/arquivo>+<Enter>.
  • Salvar com outro nome: no modo de comando, teclamos <:w>+<novo.nome>+<Enter>.


Uma lista de comandos resumida segue abaixo:

  • 0: vai para o início da linha
  • $: vai para o final da linha
  • gg: vai para a primeira linha
  • G: vai para a última linha
  • :n: vai para a linha n (n é um número)
  • w: vai para a próxima palavra
  • b: vai para a palavra anterior
  • x: apaga um caractere à direita do cursor
  • X: apaga um caractere à esquerda do cursor
  • dd: apaga-se uma linha inteira
  • D: apaga do cursor até o final da linha
  • dw: apaga até a próxima palavra
  • dfs: apaga até a próxima ocorrência do caractere s
  • a: entra-se em inserção uma posição à frente do cursor
  • i: entra-se em inserção uma posição antes do cursor
  • rc: substitui o caractere sob o cursor pelo caractere c
  • cwnova: substitui a palavra a partir do cursor pela palavra nova
  • :w: grava o arquivo
  • :w um_arquivo: grava o conteúdo no arquivo um_arquivo
  • :w! um_arquivo: grava o conteúdo no arquivo um_arquivo, sobrescrevendo-o caso exista
  • :r um_arquivo: lê um_arquivo e insere seu conteúdo a partir do cursor
  • :r!comando: executa comando no shell, e insere seu resultado a partir do cursor
  • :q: sai do vi (termina o editor)
  • :q!: sai do vi, descartando as modificações

Outros editores ?

Há muitos outros editores de texto ! Se tiver curiosidade, faça um pesquisa na Web sobre os editores de texto que existem para o Linux.


Atividade

Usando os três editores faça os seguintes exercícios:

  1. Crie e edite um arquivo contendo seus dados pessoais, de forma que possam ser usados em sua assinatura de email. Salve-o com nome signature.txt.
  2. Edite o arquivo Leiame.txt. Logo após suas duas primeiras linhas (título de seu conteúdo), adicione uma linha com seu nome, matrícula e turma. Salve o arquivo modificado.
  3. Em Leiame.txt acrescente a data de hoje após a última linha.
  4. Em Leiame.txt remova a 2a questão. Apague também a linha em branco logo a seguir. Em seguida renumere as próximas questões, para que fiquem na sequência correta.
  5. Em Leiame.txt localize a 3a ocorrência das palavras "diretorio" ou "diretorios", e remova-a. Localize então a ocorrência imediatamente anterior, e substitua por maiúsculas.
  6. Em Leiame.txt localize as ocorrências da palavra “diretorio”, e substitua por “subdiretorio”, com exceção de quando se referir ao diretório raiz. Salve o arquivo modificado.
  7. Em Leiame.txt, acrescente o resultado da listagem do diretório /home logo após a questão 5.
  8. Salve o arquivo resultante com o nome Leiame2.txt. O arquivo resultante deve ter mais ou menos este conteúdo.

24/08: Compactadores de arquivos

Uma primeira forma de compactar arquivos no Linux é usando o gerenciador de arquivos nautilus. Por exemplo, ra compactar um diretório deve-se selecioná-lo e em seguida chamar o pop-up menu (botão direito do mouse):


Compress1.png


Ao se escolher a opção Comprimir, uma janela irá surgir para que se defina o nome do arquivo compactado e o tipo de compactação a ser usada:


Compress2.png


O arquivo compactado aparecerá na listagem de arquivos do nautilus:


Compress3.png


Para descompactá-lo e visualizar seu conteúdo, basta clicar duas vezes nele:


Compress4.png


Exercício

Obtenha este arquivo, e descompacte-o em algum subdiretório. Em seguida recompacte-o usando os diferentes formatos de compactação.

Compactadores no modo texto

Vários compactadores de arquivos existem no Linux, e o nautilus simplifica sua seleção e uso. Esses compactadores podem ser usados também no modo texto ... aliás, eles originalmente foram criados para serem usados dessa forma ! O que o nautilus faz é facilitar seu uso por meio de uma interface gráfica.

Os principais compactadores são:

  • compress: compactador mais antigo e comum nos Unix em geral, porém em desuso. Gera arquivos compactados com extensão .Z. Precisa do pacote de software ncompress no Ubuntu. Exemplo de uso:
    msobral@dell-iron:~$ ls -l API-changes.txt 
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$ compress API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 22781 2010-03-24 11:32 API-changes.txt.Z
    msobral@dell-iron:~$ uncompress API-changes.txt.Z 
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • GNU zip: compactador bastante utilizado, com maior poder de compactação que compress. Gera arquivos compactados com extensão .gz. Já vem instalado no Ubuntu. Exemplo de uso:
    msobral@dell-iron:~$ gzip API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 17651 2010-03-24 11:32 API-changes.txt.gz
    msobral@dell-iron:~$ gunzip API-changes.txt.gz
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • bzip2: vem sendo bastante usado por ter um poder de compactação ainda maior, porém à custa de maior processamento (compactação fica mais lenta). Gera arquivos compactados com extensão .bz2. Também já vem instalado no Ubuntu.
    msobral@dell-iron:~$ bzip2 API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 15804 2010-03-24 11:32 API-changes.txt.bz2
    msobral@dell-iron:~$ bunzip2 API-changes.txt.gz
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • ... outros menos populares no mundo do Linux, tais como zip, rar e zoo.

Note que os compactadores compress, gzip, e bzip2 compactam um arquivo por vez. Assim, com eles não é possível juntar vários arquivos e diretórios dentro de um único arquivo compactado (o que se faz corriqueiramente com zip ou rar ...). Portanto, se for necessário compactar um diretório ou um conjunto de arquivos, o melhor é combinar um compactador com o programa tar.

tar

O programa tar é um utilitário do mundo Unix originalmente criado para backups em fita (daí seu nome: TApe aRchiver, se bem que tar é também um trocadilho que pode significar piche, pois ele de certa forma gruda um arquivo ao outro). O resultado da execução do tar é um arquivo contendo todos os arquivos e diretórios que foram selecionados para inclusão. Esse arquivo tar pode ser então compactado, obtendo-se algo parecido com o que faz zip ou rar.

Mas porque não usar então zip e rar ? Afinal, eles existem também no Linux ... No entanto, esses compactadores nasceram no mundo do antigo MS-DOS, e assim não são capazes de armazenar todos os atributos de arquivos que existem em sistemas Unix (informações tais como usuário e grupo dono do arquivo, permissões de acesso, tipo do arquivo, datas de último acesso e modificação). O tar, pelo contrário, consegue preservar esses atributos, e por isto se torna mais adequado para uso no Unix em geral.

Uso do tar:

  • Criação de arquivo tar:
    tar cf nome_arquivo.tar arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
    
  • Mostrar o conteúdo de arquivo tar:
    tar tvf nome_arquivo.tar
    
  • Extrair conteúdo de arquivo tar:
    tar xf nome_arquivo.tar
    

Os usos acima não compactam os arquivos incluídos dentro do arquivo tar. Para compactá-los deve-se adicionar uma opção de compactação:

  • Criação de arquivo tar compactado:
    • Com compress:
      tar cZf nome_arquivo.tar.Z arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
    • Com gzip:
      tar czf nome_arquivo.tar.gz arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
    • Com bzip2:
      tar cjf nome_arquivo.tar.bz2 arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
  • Mostrar o conteúdo de arquivo tar:
    • Com compress:
      tar tvZf nome_arquivo.tar.Z
      
    • Com gzip:
      tar tvzf nome_arquivo.tar.gz
      
    • Com bzip2:
      tar tvjf nome_arquivo.tar.bz2
      
  • Extrair conteúdo de arquivo tar:
    • Com compress:
      tar xZf nome_arquivo.tar.Z
      
    • Com gzip:
      tar xzf nome_arquivo.tar.gz
      
    • Com bzip2:
      tar xjf nome_arquivo.tar.bz2
      

Atividade

Faça os exercícios abaixo usando o nautilus e os compactadores no modo texto:

  1. Procure um arquivo de texto (extensão .txt, .html, ou .doc) com ao menos 100 kB e compacte-o com compress, gzip e bzip2. Compare os tamanhos dos arquivos resultantes.
  2. Usando o programa tar, compacte todo o diretório home do usuário aluno. Experimente criar o arquivo tar sem compactação, e depois compactado com cada um dos compactadores vistos. Você terá portanto como resultado quatro arquivos tar diferentes ...
  3. Descompacte os arquivos tar gerados na questão anterior. Para evitar sobreposição, descompacte cada um deles em um diretório separado.
  4. Resolva a prova que foi aplicada no semestre 2009.2.

30/08: Avaliação

Avaliação teórica e prática

Lógica de Programação

31/08: Introdução

Assuntos: Lógica de programação: instrução, sequência lógica, algoritmo.

Referências auxiliares:


Um primeiro algoritmo


Videos sobre algoritmos:

Exemplificando com shell scripts:

#!/bin/bash

# Cada linha no script abaixo corresponde a uma instrução ...
# O conjunto de instruções na ordem apresentada forma uma sequência lógica ...

echo Iniciando o script ...
echo Vou procurar todos os arquivos de texto existentes neste diretório

find . -type f -name "*.doc" > .tmp
find . -type f -name "*.txt" >> .tmp
find . -type f -name "*.rtf" >> .tmp
find . -type f -name "*.odt" >> .tmp

echo Os arquivos são:

cat .tmp

rm -f .tmp

Problemas exemplo

Problema dos três recipientes

Há três recipientes com tamanhos distintos: um com 8 litros, outro com 5 litros e o terceiro com 3 litros. O recipiente com 8 litros está completamente cheio. Deseja-se colocar 4 litros em dois recipientes. Considere que os recipientes não são graduados.


Problema da travessia

Um barqueiro precisa levar um saco de milho, uma galinha e uma raposa para o outro lado do rio. Porém o barco somente é capaz de levar uma coisa de cada vez (além do barqueiro). Qual a sequência de travessias necessário para atravessar o milho, a galinha e a raposa ?

Torres de Hanoi

Há três hastes. Uma das hastes serve de suporte para três discos de tamanhos diferentes. Um disco menor sempre é colocado sobre um disco maior. A figura abaixo ilustra as hastes e os discos:

Hanoi.png

Desejam-se mover os três discos para a haste da direita. Porém só pode se mover um disco por vez, e um disco maior nunca pode ficar sobre um disco menor.

Operação possível: Move disco para haste

Qual a sequência de operações para mover os discos de uma haste para outra ?

Atividade extra

  • O jogo LightBot mostra de uma forma divertida como criar pequenos algoritmos. Até que fase desse jogo você consegue chegar ?

Leitura adicional

Conceitos da 1a avaliação

Aluno Teorica Pratica
Fernando A D
Gabriel D D
Levi D D
Lindalvo D D
Marine D D
Mario Allan A B
Mário André B C
Mário Sérgio C D
Maykon A C
Nathany B D
Paulo Igor A D
Ricardo C D
Roberto A B
Thiago Martins C D
Thiago Ramos C D
Vinicius Kachniacz C C
Vinicius Rodrigues A D

06/09: Algoritmos

Ver transparências.

Introdução a lógica de programação:

  • Algoritmos: sequência finita de passos que leva à execução de uma tarefa. Exemplos:
    1. Como resolver o cubo de Rubik (cubo mágico)
    2. Cálculo das raízes de uma equação de 2o grau (método de Baskara)
    3. Receita de pão
    4. Soma de dois números:
      Ler primeiro número
      Ler segundo número
      Somar os dois números lidos
      Mostrar o resultado
      
  • Programa: tradução de um algoritmo para uma linguagem de programação, para que possa ser executado por um computador.
    1. Soma de dois números em shell script:
      #!/bin/bash
      
      echo -n Entre com o primeiro numero:
      read x
      echo -n Entre com o segundo numero:
      read y
      z=$(($x + $y))
      
      echo A soma de $x e $y eh $z
      
      Para executar esse programa, grave-o em um arquivo chamado soma.sh e em seguida faça o seguinte:
      bash soma.sh
      
    2. Soma de dois números em Linguagem C:
      #include <stdio.h>
      
      int main() {
        int x, y, r;
      
      
        printf("Entre com o primeiro numero: ");
        scanf("%d", &x);
      
        printf("Entre com o segundo numero: ");
        scanf("%d", &y);
      
        r = x + y;
      
        printf("A soma de %d e %d eh %d\n", x, y, r);
      
        return 0;
      }
      
      Para executar esse programa, grave-o em um arquivo chamado soma.c e em seguida faça o seguinte:
      gcc -o soma soma.c
      ./soma
      
    3. Soma de dois números em Java:
      import java.util.Scanner;
      
      class Soma
      {  
              public static void main(String args[])
              {
      	   int  x, y, r;
      	   Scanner scanner = new Scanner(System.in);
      	
                 System.out.print("Entre com o primeiro numero: ");
      	   x = scanner.nextInt();
      
                 System.out.print("Entre com o segundo numero: ");
      	   y = scanner.nextInt();
      
      	   r = x + y;
      
      	   System.out.println("A soma de " + x + " e " + y + " eh " + r);
              }
      }
      
      Para executar esse programa, grave-o em um arquivo chamado Soma.java e em seguida faça o seguinte:
      javac Soma.java
      java Soma
      
    4. Soma de dois números em Python:
      #!/usr/bin/python
      
      import sys
      
      print "Entre com o primeiro numero: ",
      x = int(sys.stdin.readline())
      
      print "Entre com o segundo numero: ",
      y = int(sys.stdin.readline())
      
      r = x + y
      
      print "A soma de", x, "e", y, "eh", r
      
      sys.exit(0)
      
      Para executar esse programa, grave-o em um arquivo chamado soma.py e em seguida faça o seguinte:
      python soma.py
      

Como mostrado acima, o mesmo algoritmo foi traduzido para programas em diferentes linguagens de programação. Ao serem executados, geraram o mesmo resultado.

Exercícios: desenho de figuras geométricas

  1. Usando apenas as instruções:
    acendeCaneta
    apagaCaneta
    avança X
    giraDireita angulo
    giraEsquerda angulo
    fazArco X graus, raio Y
    
    escreva algoritmos para desenhar a figura entregue pelo professor. Não mostre sua figura para as outras equipes.
  2. kturtle é um software educacional para ajudar no ensino de matemática, geometria e introdução à programação. Ele possibilita fazer desenhos facilmente, seguindo um programa com instruções de desenho. Usando as instruções:
    reset (move a tartaruga para o centro da tela)
    clear (limpa a tela)
    pendown (põe a caneta no papel - acendeCaneta)
    penup (levanta a caneta - apagaCaneta)
    forward X (avança X posições)
    turnright angulo (gira pra direita)
    turnleft angulo (gira pra esquerda)
    
    ... escreva programas para os algoritmos criados no ítem anterior.

    Guia de referência completo do Kturtle
  3. Usando o kturtle escreva algoritmos para desenhar as seguintes figuras:
    • triângulo equilátero
    • triângulo isósceles
    • triângulo escaleno
    • quadrado
    • hexágono
    • octógono
    • quadrado com vértices interligados
    • Um círculo
    • 7 hexágonos interligados (um central e seis periféricos).
    • 7 círculos interligados (um central e seis periféricos), parecendo uma flor
  4. Fractais são figuras nas quais cada pedacinho é semelhante à toda figura. Um fractal bastante simples de criar é o Floco de Neve Koch, cuja criação pode ser entendida na sequência de figuras abaixo:

Koch0.png
Primeira iteração

Koch1.png
Segunda iteração

Koch2.png
Terceira iteração

Koch3.png
Próximas iterações

Usando o kturtle desenhe essas figuras, reproduzindo o maior número de iterações que conseguir. Você consegue descobrir uma regra para gerá-las ?

Obs: fonte dessas figuras

Dicas para o kturtle

  1. Pode-se repetir uma sequência de instruções usando-se o comando repeat. Por exemplo, para desenhar um pentágono usando repeat:
    repeat 5 {
      forward 50
      turnleft 72
    }
    
  2. Podem-se usar variáveis para generalizar os algoritmos. Uma variável tem um identificador, que deve ser precedido do caractere $:
    $x=5
    $lado=50
    repeat $x {
      forward $lado
      turnleft 360/$x
    }
    
  3. Pode-se usar o comando ask para ler do teclado valores a serem usados no algoritmo de desenho:
    $x = ask "Quantos lados tem o polígono ?"
    $lado = ask "Qual o comprimento de cada lado ?"
    repeat $x {
      forward $lado
      turnleft 360/$x
    }
    
  4. Por fim, com o comando learn é possível criar novos comandos no kturtle. Por exemplo, para criar um comando que desenhe um triângulo:
    learn triangulo $lado {
     repeat 3 {
      forward $lado
      turnleft 120
     }
    }
    

Esse novo comando desenha um triângulo equilátero cujos lados tem comprimento dado pelo parâmetro $lado. Ele poderia ser usado assim em um algoritmo:

learn triangulo $lado {
 repeat 3 {
  forward $lado
  turnleft 120
 }
}
triangulo 50
triangulo 100
triangulo 100

Nesse exemplo, três triângulos são desenhados: um com lado 50, outro com lado 100, e um terceiro com lado 150. Veja que o número escrito logo após o comando triangulo irá aparecer no lugar de $lado no algoritmo que desenha o triângulo.

13/09: Algoritmos

Sobre a atividade da aula passada:


Os algoritmos que iremos criar serão compostos de:

  • Estruturas de controle: estruturas para controlar a sequência de execução (realização) de algoritmos:
    • Decisão: para realizar testes de forma a decidir que sequências de instruções devem ser executadas
    • Repetição: para repetir sequências de instruções
  • Estruturas de dados: estruturas para representar os dados a serem processados por algoritmos
    • Variáveis e constantes

Portugol

As aulas de Lógica de Programação usarão um software de auxílio ao ensino de algoritmos chamado Portugol, desenvolvido na Escola Superior de Engenharia do Instituto Politécnico de Tomar, em Portugal.

Guia rápido de instalação e utilização do Portugol

Abaixo segue uma breve ajuda de como obtê-lo, instalá-lo e usá-lo. Esse guia assume que você esteja usando o Ubuntu Linux 9.04 ou superior.

  1. Faça o download do Portugol.
  2. Descompacte-o com o seguinte comando:
    tar xzf portugol23.tar.gz
    
  3. Repare que existe agora um subdiretório portugol no diretório onde você o descompactou. Execute o Portugol com o seguinte comando:
    java -jar portugol/Portugol.jar
    
    Obs: você precisará ter Java instalado. Caso não o tenha, execute o comando:
    sudo apt-get install openjdk-6-jre
    
  4. Copie esse arquivo para poder ver fluxogramas coloridos, e grave-o no memso diretório onde está o Portugol.
  5. Veja a ajuda do Portugol, e use-a sempre que tiver dúvidas !


A tela inicial do Portugol segue abaixo, junto com um programa demonstrativo.

Editor-Portugol.png

Exemplos de programas iniciais em Portugol:

  1. Lendo um número e mostrando-o na tela em seguida:
    Inicio
      inteiro x
    
      Escrever "Digite um numero: ",
      Ler X
      Escrever "Numero digitado: ", x
    Fim
    
  2. Lendo dois números, somando-os e mostrando o resultado na tela:
    Inicio
      inteiro x, y
    
      Escrever "Digite um numero: ",
      Ler x
      Escrever "Digite outro numero: ",
      Ler y
      Escrever "Soma = ", x+y
    Fim
    
    O programa abaixo é equivalente:
    Inicio
      inteiro x, y, z
    
      Escrever "Digite um numero: ",
      Ler x
      Escrever "Digite outro numero: ",
      Ler y
      z <- x + y
      Escrever "Soma = ", z
    Fim
    

Atividades

  1. Média de três números: escreva um programa para calcular a média de três números.
  2. Média balanceada de três números: escreva um programa para calcular a média balanceada de três números.
  3. Sequência de Fibonacci: em matemática corresponde aos números:
    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
    
    ... que pode ser descrita pela relação de recorrência



    ... com valores iniciais e .

    Numerosas formas na natureza apresentam essa sequência, como neste girassol (cujas flores se dispõem em uma espiral):

    Sunflower.jpg Espiral fibonacci.png FibonacciBlocks.png

    Usando o Portugol escreva um programa que mostre os 10 primeiros números dessa sequência.
  4. Distância até o horizonte: escreva um programa que calcule a distância dos seus olhos até o horizonte. Assuma que a Terra é perfeitamente esférica, e que seu raio tem 6.378 km. Considere que você esteja no nível do mar (seus pés tocando a água do mar ;-), e que o horizonte esteja num mar perfeitamente liso. Dica: faça um diagrama desse problema para visualizar sua geometria, e use trigonometria para resolvê-lo.

14/09: Algoritmos

  • Diagrama de blocos (fluxograma)
  • Variáveis e constantes

Fluxogramas

Diagramas de bloco para auxiliar a descrição de algoritmos. Ajudam na compreensão do algoritmo, por poder visualizar o fluxo de execução.


Fluxograma-soma.png Fluxograma para o algoritmo da média de trẽs números.


Blocos de uso mais comum

Bloco Descrição Exemplo
Inicio.png Inicio do fluxograma
Processamento.png Processamento
Entrada.png Entrada de dados (ler do teclado)
Saida.png Saída de dados (mostrar na tela)
Decisao.png Decisão (testar uma condição e bifurcar) Ex-decisao.png
Conector.png Conector (juntar dos ou mais ramos do fluxograma) Ex-conector.png
Fim.png Fim

Obs: Arquivo de configuração das cores do fluxograma do Portugol.

Variáveis e constantes

  • Variável: capaz de guardar um dado a ser usado no algoritmo. Pode ser entendida como uma caixa, onde se coloca um dado e se pode consultá-lo quantas vezes for necessário. O dado pode ser modificado (substituído por outro). Exemplo em Portugol:
    Inicio
      inteiro anos, dias
    
      Escrever "Quantos anos se passaram ? "
      Ler anos
      dias <- anos * 365
      Escrever "... então se passaram ", dias, " dias"
    Fim
    
    Nesse exemplo há duas variáveis: dias e anos
  • Constante: semelhante à variável, porém o dado armazenado não pode ser modificado. Exemplo em Portugol:
    Inicio
      constante inteiro diasPorAno <- 365
      inteiro anos, dias
    
      Escrever "Quantos anos se passaram ? "
      Ler anos
      dias <- anos * diasPorAno
      Escrever "... então se passaram ", dias, " dias"
    Fim
    
    Nesse exemplo há uma constante: diasPorAno


Variáveis e constantes devem ser declaradas antes de serem usadas (algumas poucas linguagens, como Python e Perl, não exigem isto). A declaração consiste do tipo e identificador da variável. O tipo corresponde ao tipo de valor que pode ser guardado, e o identificador é o nome da variável. No exemplo abaixo:

  constante inteiro diasPorAno <- 365
  inteiro anos, dias
Fim

No exemplo acima, há duas variáveis do tipo inteiro, e seus identificadores são dias e anos. O tipo inteiro indica que essas variáveis podem guardar somente números inteiros.

Tipos de variáveis e constantes no Portugol:

Tipo Descrição Exemplo
Inteiro Número inteiro entre -2 147 483 648 e 2 147 483 647 Inteiro x <- 10
Real Número real entre -1.7 E 308 e 1.7 E 308 Real y <- 10.789
Lógico Valor booleano, com valores "Verdadeiro" e "Falso" Logico ok <- Falso
Caracter Um caractere da tabela ASCII Caracter letra <- "A"
Texto Uma sequência de caracteres (ou string) Texto palavra <- "um teste"

A declaração de constantes é semelhante à de variáveis, bastanto prefixá-las com a palavra-chave constante.

Expressões aritméticas

Um conjunto de operações sobre variáveis, constantes e funções numéricas, e que gera um determinado resultado numérico.

Exemplos de expressões aritméticas:

# Uma expressão que calcula quantos segundos existem em um horário do tipo horas, minutos e segundos
3600*horas + 60*minutos + segundos

# Uma expressão que calcula a velocidade instantânea, segundo um MRV
vel_inicial + aceleracao*tempo;

# Uma expressão que calcula o módulo de um vetor bidimensional, que possui coordenadas x e y
raiz(x^2 + y^2)

Os resultados de expressões podem ser mostrados na tela, ou armazenados em variáveis:

# Uma expressão que calcula quantos segundos existem em um horário do tipo horas, minutos e segundos
segundos <- 3600*horas + 60*minutos + segundos

# Uma expressão que calcula a velocidade instantânea, segundo um MRV
escrever 'Velocidade no instante ', tempo, ' = ', vel_inicial + aceleracao*tempo;

# Uma expressão que calcula o módulo de um vetor bidimensional, que possui coordenadas x e y
modulo <- raiz(x^2 + y^2)

Repare que uma expressão fica sempre do lado direito, quando atribuída a uma variável. A expressão é primeiro calculada, e em seguida seu resultado é armazenado na variável:

segundos <- 3600*horas + 60*minutos + segundos

Operadores aritméticos

Expressões aritméticas sao compostas por números e operadores aritméticos:

Obs: para os exemplos abaixo são usadas estas variáveis:

Real x, area, lado
inteiro dias, horas
Operador Descrição Exemplo
+ Adição x <- x + 1
- Subtração x <- x - 1
* Multiplicação x <- x*x*x
/ Divisão dias <- horas / 24
% Módulo (resto de divisão) horas <- horas % 24
^ Potenciação area <- lado^2

Precedência dos operadores (nesta ordem): ^, *, /, %, + e -

A precedência pode ser modificada com o uso de parênteses. Ex:

escrever 1 + 2 * 3
escrever (1 + 2)*3

No Portugol, existem também algumas funções úteis, como a função raiz:

r <- raiz(x^2 + y^2)

O resultado de expressões aritméticas depende dos tipos numéricos das variáveis e constantes:

inicio
  real x
  inteiro y
  inteiro resultadoInteiro
  real resultadoReal
  
  x <- 9
  y <- 9
  
  escrever "O resultado de uma expressão aritmética depende dos tipos das variáveis e constantes\n"
  escrever "usadas na expressão. Se forem todas inteiras, então o resultado será inteiro.\n"
  escrever "Veja este exemplo: \n"
  escrever "Variável inteira y=", y
  escrever "\nExpressão: y/2=", y/2
  
  escrever "\n\nNeste segundo exemplo, repete-se a mesma expressão, porém usando-se uma\n"
  escrever "variável real:\n"
  escrever "Variável real x=", x
  escrever "\nExpressão: x/2=", x/2
  
  x <- 4
  y <- 5
  escrever "\n\nSe as variáveis de diferentes tipos forem combinadas, o resultado da\n"
  escrever "expressão será real:\n"
  escrever "Variável real x=", x, " e inteira y=", y
  escrever "\nExpressão: (x+y)/2=", (x+y)/2

  escrever "\n\nNo entanto, se uma expressão tiver um resultado real, mas este for\n"
  escrever "atribuído a uma variável inteira, então apenas a parte inteira será guardada:\n"
  escrever "Variável real x=", x, " e inteira y=", y
  y <- (x+y)/2
  escrever "\nExpressão: y <- (x+y)/2 ... após executada, y=", y
  
fim

Atividade

Para os exercícios abaixo, desenhe o fluxograma e escreva o algoritmo no Portugol.

  1. Faça um algoritmo que, usando somente duas variáveis, calcule a média de quatro números.
  2. Escreva um algoritmo que calcule as raizes de uma equação de 2o grau.
  3. Um equipamento conta o tempo desde que foi ligado. No entanto, essa contagem é feita em segundos. Faça um algoritmo que converta o valor desse contador para horas, minutos e segundos. Ex: se o contador tiver o valor 43397, o seu programa deve mostrar: 12:03:17.
  4. Crie um conversor de decimal para binário (limite: 4 bits). Ex.: tendo o número 10 (decimal) de entrada, deve-se obter o número 1010 (binário) de saída.
  5. Escreva um algoritmo que leia o nome, sobrenome e idade de uma pessoa, e escreva na tela (no lugar dos colchetes devem aparecer os valores lidos):
     Nome: [sobrenome, nome]
     Idade: [idade] anos
    
  6. Crie um gerador automático de código Logo para desenhar polígonos:
    • Ler um número do usuário.
    • Calcular o ângulo interno.
    • Apresentar como resultado o código Logo a ser inserido no programa kturtle. Ex.: se o usuário digitar o número 3, o código será de um triângulo equilátero, cuja soma dos ângulos internos é 180 - logo, cada ângulo será de 60 graus (no Logo, lembre-se que o ângulo a ser usado é o complemento de 180, conforme visto em aula). Se o usuário digitar 5 ao invés de 3, teremos um pentágono. Abaixo temos soluções para triângulo e pentágono:
reset
repeat 3
{
  forward 100
  turnright 120
}
reset
repeat 5
{
  forward 100
  turnright 72
}


20/09: Estruturas de decisão

O exemplo abaixo está contido no livro Classification and Regression Trees, de Leo Breiman, Jerome Friedman, Richard Olshen e Charles Stone, editora Chapman & Hall, 1984.

Na Universidade da California, no centro Médico de San Diego, quando um paciente com ataque cardíaco é recebido, dezenove variáveis são medidas ao longo das primeiras 24 horas. Essas incluem pressão sanguínea, idade, e 17 outras variáveis ordenadas e binárias (booleanas) que sumarizam os sintomas médicos considerados importantes indicadores da condição do paciente.

O objetivo de um estudo médico feito entre os anos 70 e 80 foi o desenvolvimento de um método para identificar pacientes de alto risco (que não sobreviverão ao menos 30 dias) com base nos dados obtidos nas primeiras 24 horas. O diagrama abaixo mostra uma regra de classificação que foi produzida nesse estudo. A letra F significa que não há um risco alto, e a letra G quer dizer paciente de alto risco.

Crt-decisao.png

Essa regra classifica os pacientes como F ou G dependendo de respostas do tipo sim/não a no máximo três perguntas. Como seria um algoritmo que a implementasse ?


Algoritmos para resolver problemas como o exemplo acima dependem de se poder expressar a tomada de decisões. Deve ser possível testar condições, como por exemplo "a idade é maior que 62.5 anos ?", e executar instruções dependendo do resultado do teste. Em Lógica de Programação, e em linguagens de programação em geral, isso se faz com estruturas de decisão.

Estruturas de decisão possibilitam que se executem diferentes sequências de instruções de um programa, dependendo de uma condição a ser avaliada. Por exemplo, um jogo poderia armazenar a maior pontuação já obtida, e verificar se foi ultrapassada ao final de cada partida:

  Se pontuacao > recorde então 
    recorde <- pontuação
  FimSe

O exemplo em Portugol acima mostra a estrutura de decisão Se condição entao comandos Fimse. O equivalente em fluxograma é:

Seentao.png

Veja o próximo exemplo:

  Se conceito > 70 entao
    escrever 'Voce esta aprovado'
  senao
    escrever 'Desta vez não deu ... tente de novo !'
  Fimse

O uso de Se condição entao comandos Senao comandos Fimse possibilita que se execute uma sequência de comandos se a condição for verdadeira, e outra sequência se for falsa. Seu equivalente em fluxograma é:

Seentaosenao.png

Para fazer um bom uso de estruturas de decisão deve-se primeiro conseguir identificar as condições a serem avaliadas. Condições são escritas com expressões lógicas, e estas são compostas de operadores lógicos e relacionais aplicados a variáveis e constantes.

Condições

Condições representam os testes que precisam ser feitos com dados do problema. Esses testes são expressados por expressões lógicas, cujos resultados são verdadeiro ou falso. Expressões lógicas são construídas usando-se operadores lógicos e operadores relacionais para comparar e avaliar os valores de variáveis e constantes.

Obs: para os exemplos abaixo são usadas estas variáveis:

Logico correto, multa, aprovado, barato, bombear_agua
Logico descartar, baixo, reprovado, erro, enviado, recebido
inteiro erros, pontuacao, preco, endereco, velocidade
Real faltas, nivel_agua, altura

Operadores relacionais

Operadores relacionais são usados para comparar valores, e estão listados na tabela abaixo. Cada comparação feita com esses operadores forma uma expressão lógica simples. Portanto, o resultado de uma comparação é um valor lógico que pode ser verdadeiro ou falso.

Operador Descrição Exemplo
= Igualdade correto <- (erros = 0)
> Maior multa <- (velocidade > 80)
>= Maior ou igual aprovado <- (pontuacao >= 70)
< Menor barato <- (preco < 100)
<= Menor ou igual bombear_agua <- (nivel_agua <= 0.7)
=/= Diferente descartar <- (endereco =/= 12345)

Operadores lógicos

Operadores lógicos são usados para combinar expressões lógicas simples, criando assim expressões lógicas compostas, e estão listados na tabela abaixo.

Operador Descrição Exemplo
NAO Negação baixo <- NAO (altura > 1.8)
E Conjunção aprovado <- NAO (conceito = "D") E (faltas <= 0.25)
OU Disjunção reprovado <- (conceito = "D") OU (faltas > 0.25)
XOU Disjunção exclusiva erro <- enviado XOU recebido

Precedência dos operadores (nesta ordem): NAO, E, OU e XOU

Lembre que a precedência pode ser modificada com o uso de parênteses.

Atividades

  1. Faça um programa que leia um número e então informe se ele é par ou ímpar.
  2. Um radar de trânsito faz a medição de velocidade de veículos e, dependendo do valor, calcula a multa a ser aplicada. Em uma determinada via esse radar foi configurado da seguinte forma:
    • Se a velocidade for maior que 80 km/h, a multa é de R$ 360.
    • Se a velocidade for maior que 60 km/h, a multa é de R$ 180.
    • Se a velocidade for menor ou igual a 60 km/h, não há multa.

      Escreva um algoritmo que calcule a multa de acordo com a velocidade de um veículo.
  3. Faça um algoritmo que leia três números do teclado, e mostre o maior e menor números.
  4. Escreva um algoritmo que faça o teste de risco de paciente cardíaco, mostrado no início da aula.
  5. Um estudo sobre sensibilidade de pessoas a temperaturas da água identificou que a maioria das pessoas considera fria a água com temperaturas abaixo de 25 graus, morna entre 25 e 30 graus, e quente acima de 30 graus. Escreva um algoritmo que mostre as palavras "fria", "morna" ou "quente" dependendo da temperatura da água que for informada.
  6. Em uma rede de computadores, o firewall restringe o acesso a Internet dependendo do horário e do tipo de usuário que faz o acesso. Os tipos de usuário abaixo têm as seguintes restrições:
    • Funcionario: apenas entre 0:00 e 7:30, entre 18:30 e 0:00, e entre 12:00 e 13:30
    • Financeiro: qualquer horario
    • Diretoria: qualquer horário
      Escreva um algoritmo que informe se um acesso foi permitido, em função do horário e do tipo de usuário.
  7. Modifique o algoritmo acima para adicionar a seguinte restrição:
    • Funcionario: nao pode acessar sites de jornal (ex: www.rbs.com.br)
    • Financeiro: nao pode acessar sites de jornal durante o expediente
    • Diretoria: sem restrições a sites
  8. Faça um algoritmo para fazer a divisão de dois números reais. Antes de dividi-los deve ser feito um teste de validade. Caso não seja possível dividi-los, deve ser mostrada uma mensagem de erro. Se for possível, deve-se mostrar o resultado da divisão.
  9. Faça um jogo de par ou ímpar, em que o jogador aposta contra o computador. O jogador deve digitar um número entre 0 e 5 e optar entre par ou ímpar. O computador deve sortear um número também entre 0 e 5. Se a paridade da soma dos números do jogador e do computador for a mesma que o jogador optou, então ele ganha a partida, senão o computador vence.
  10. Escreva um algoritmo para identificar se há, dentre três palavras lidas do teclado, ao menos duas palavras distintas que pertençam ao conjunto {azul, preto, vermelho}. Exemplos:
    • Se o usuário digitar verde, preto, vermelho, o programa deve mostrar na tela verdadeiro
    • Se o usuário digitar verde, preto, preto, o programa deve mostrar na tela falso
    • Se o usuário digitar azul, preto, azul, o programa deve mostrar na tela verdadeiro
      Solução vista em aula:
      // Neste algoritmo deve-se identificar se ao menos duas palavras
      // diferentes têm os valores azul, preto ou vermelho.
      // A variável inteira "cont" conta quantas palavras diferentes
      // tem esses valores.
      
      inicio
          texto p1 , p2 , p3
          inteiro cont <- 0
          
          escrever "Palavra 1: "
          ler p1
          escrever "Palavra 2: "
          ler p2
          escrever "Palavra 3: "
          ler p3
          
          // ao menos uma palavra é "azul" ?
          se p1 = "azul" OU p2 = "azul" OU p3 = "azul" entao
            cont <- 1
          fimse
      
          // ao menos uma palavra é "preto" ?
          se p1 = "preto" OU p2 = "preto" OU p3 = "preto" entao
            cont <- cont + 1
          fimse
      
          // ao menos uma palavra é "vermelho" ?
          se p1 = "vermelho" OU p2 = "vermelho" OU p3 = "vermelho" entao
            cont <- cont + 1
          fimse
      
          // se duas ou mais palavras diferentes têm aqueles valores,
          // então mostra VERDADEIRO
          se cont > 1 entao
            escrever "VERDADEIRO"
          senao
            escrever "FALSO"
          fimse
              
      fim
      

21/09: estruturas de decisão

Há situações em que se precisa fazer um conjunto de comparações, como mostrado abaixo:

// Lê a data no formato numérico dia, mes, ano, e mostra a data no formato
// dia, nome do mês, ano.
Inicio
  inteiro dia, mes, ano
  texto nome_mes

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  se mes = 1 entao
    nome_mes <- "Janeiro"
  senao
    se mes = 2 entao
      nome_mes <- "Fevereiro"
    senao
      se mes = 3 entao
        nome_mes <- "Março"
      senao
        se mes = 4 entao
          nome_mes <- "Abril"
        senao
          se mes = 5 entao
            nome_mes <- "Maio"
          senao
            se mes = 6 entao
              nome_mes <- "Junho"
            senao
              se mes = 7 entao
                nome_mes <- "Julho"
              senao
                se mes = 8 entao
                  nome_mes <- "Agosto"
               senao
                  se mes = 9 entao
                    nome_mes <- "Setembro"
                  senao
                    se mes = 10 entao
                      nome_mes <- "Outubro"
                    senao
                      se mes = 11 entao
                        nome_mes <- "Novembro"
                      senao
                        nome_mes <- "Dezembro"
                      fimSe
                    fimSe
                  fimSe
                fimSe
              fimSe
            fimSe
          fimSe
        fimSe
      fimSe
    fimSe
  fimSe

  escrever dia, " de ", nome_mes, " de ", ano
fim

Além de ser trabalhoso esse encadeamento de Se ... entao ... senao, o algoritmo resultante fica pouco legível. Quer dizer, ele fica feio e difícil de entender.

Existe uma estrutura de decisão criada justamente para casos como esse, e que resulta em um algoritmo mais limpo e compreensível:

// Lê a data no formato numérico dia, mes, ano, e mostra a data no formato
// dia, nome do mês, ano.
Inicio
  inteiro dia, mes, ano
  texto nome_mes

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  Escolhe mes
    caso 1: 
      nome_mes <- "Janeiro"
    caso 2: 
      nome_mes <- "Fevereiro"
    caso 3: 
      nome_mes <- "Março"
    caso 4: 
      nome_mes <- "Abril"
    caso 5: 
      nome_mes <- "Maio"
    caso 6: 
      nome_mes <- "Junho"
    caso 7: 
      nome_mes <- "Julho"
    caso 8: 
      nome_mes <- "Agosto"
    caso 9: 
      nome_mes <- "Setembro"
    caso 10: 
      nome_mes <- "Outubro"
    caso 11: 
      nome_mes <- "Novembro"
    Defeito: 
      nome_mes <- "Dezembro"
  fimEscolhe

  escrever dia, " de ", nome_mes, " de ", ano
fim

A estrutura de decisão escolhe ... caso tem uma certa flexibilidade. No exemplo abaixo, mostra-se a possibilidade de testar mais de um valor no mesmo caso:

inicio     
  caracter sexo     

  escrever "Qual o seu sexo (f/m):"     
  ler sexo     

  escrever "Olá "     

  escolhe sexo         
    caso "m", "M" :             
      escrever "senhor"         
    caso "f","F" :             
      escrever "senhorita"         
    defeito :             
      escrever "Sexo indefinido"     
  fimescolhe     

  escrever ", benvindo ao portugol" 
fim

Atividades

  1. Faça um algoritmo que converta um número de 1 a 7 para o respectivo dia da semana (ex: 1 = domingo, 2 = 2a feira, e assim por diante).
  2. Faça uma calculadora com as quatro operações aritméticas. Sua calculadora deve ler (nesta ordem) o primeiro número, a operação aritmética (que deve ser informada usando o símbolo da respectiva operação: +, -, * ou /), e depois o segundo número. Ao final, seu algoritmo deve mostrar o resultado, ou uma mensagem de erro se a operação não for possível de realizar (ex: divisão por zero).
  3. A previsão do tempo na costa brasileira pode ser feita de forma aproximada usando-se um barômetro e um termômetro. Uma estimativa com boa chance de acerto se baseia na tabela abaixo:
    Previsao-barometro.png

    Faça um algoritmo que forneça uma estimativa da previsão do tempo, usando essa tabela.
  4. Faça um algoritmo que mostre qual o último dia de um determinado mês informado pelo teclado. Caso seja informado o mês 2 (fevereiro), seu algoritmo deve identificar se é ano bissexto (assim o mês tem 29 dias), ou não (mês tem 28 dias). Obs: anos bissextos são dados pelas regras (segundo o calendário Gregoriano):
    1. De 400 em 400 anos é ano bissexto.
    2. De 100 em 100 anos não é ano bissexto.
    3. De 4 em 4 anos é ano bissexto.
      Solução vista em aula: (sem considerar anos bissextos):
      inicio
            texto mes
            
            escrever "Mes: "
            ler mes
            
            escolhe mes
              caso "janeiro","março", "maio", "julho", "agosto", "outubro", "dezembro":
                escrever 31
              caso "abril", "junho", "setembro", "novembro":
                escrever 30
              caso "fevereiro":
                escrever 28
              defeito:
                escrever "mes desconhecido !"
            fimEscolhe
      fim
      

27/09: Estruturas de decisão

Na aula se fez a resolução de exercícios propostos.

  • jogo de par ou ímpar
    inicio
      inteiro numeroComputador
      inteiro numeroUsuario
      inteiro soma
      inteiro resto
      texto opcaoUsuario
      
      // sorteia um numero entre 0 e 10 para o computador
      // "aleatorio()" é uma função que gera um número real entre 0 e 1
      numeroComputador <- aleatorio()*10
      
      escrever "Escolha par ou impar: "
      ler opcaoUsuario
    
      escrever "Escolha seu numero: "
      ler numeroUsuario
      
      
      escrever "Numero do computador: ", numeroComputador
      escrever "\nNumero do usuario: ", numeroUsuario
      
      // Para fazer a verificacao do vencedor, precisa antes descobrir se
      // o resultado é par ou ímpar. O resultado se obtém somando os números do
      // computador e do usuário, e é guardado na variável "soma". Já a variável 
      // "resto" contém 0 se o resultado for par, ou 1 se for ímpar.
      soma <- numeroUsuario + numeroComputador
      resto <- soma % 2
      
      // Verifica quem venceu: se o resultado for par e o usuário escolheu "par", ou se
      // o resultado for ímpar e o usuário escolheu ímpar, então o usuário venceu. Caso
      // contrário o computador é o vencedor. 
      // Repare como se expressa a condição para descobrir o vencedor: ela usa
      // várias condições simples combinadas com operadores lógicos E e OU. 
      se (resto = 0) E (opcaoUsuario = "par") OU (resto = 1) E (opcaoUsuario = "impar") entao
        escrever "\n\nUsuario venceu :-)"
      senao
        escrever "\n\nComputador venceu :-b"
      fimSe
       
    fim
    
  • leitura de três palavras e teste se ano menos duas pertencem a um conjunto:
    // Neste algoritmo deve-se identificar se ao menos duas palavras
    // diferentes têm os valores azul, preto ou vermelho.
    // A variável inteira "cont" conta quantas palavras diferentes
    // tem esses valores.
    
    inicio
        texto p1 , p2 , p3
        inteiro cont <- 0
        
        escrever "Palavra 1: "
        ler p1
        escrever "Palavra 2: "
        ler p2
        escrever "Palavra 3: "
        ler p3
        
        // ao menos uma palavra é "azul" ?
        se p1 = "azul" OU p2 = "azul" OU p3 = "azul" entao
          cont <- 1
        fimse
    
        // ao menos uma palavra é "preto" ?
        se p1 = "preto" OU p2 = "preto" OU p3 = "preto" entao
          cont <- cont + 1
        fimse
    
        // ao menos uma palavra é "vermelho" ?
        se p1 = "vermelho" OU p2 = "vermelho" OU p3 = "vermelho" entao
          cont <- cont + 1
        fimse
    
        // se duas ou mais palavras diferentes têm aqueles valores,
        // então mostra VERDADEIRO
        se cont > 1 entao
          escrever "VERDADEIRO"
        senao
          escrever "FALSO"
        fimse
            
    fim
    
  • teste de ano bissexto, e seu uso para mostrar quantos dias tem cada mês de um determinado ano.
    inicio
          texto mes
          inteiro ano
          
          escrever "Mes: "
          ler mes
          
          escolhe mes
            caso "janeiro","março", "maio", "julho", "agosto", "outubro", "dezembro":
              escrever 31
            caso "abril", "junho", "setembro", "novembro":
              escrever 30
            caso "fevereiro":
                escrever "Ano: "
                ler ano
                
                se ano % 400 = 0 ou ano % 4 = 0 e ano % 100 =/= 0 entao
                    escrever 29
                senao
                    escrever 28
                fimse
            defeito:
              escrever "mes desconhecido !"
          fimEscolhe
    fim
    

28/09: Estruturas de repetição

Alguns algoritmos vistos anteriormente possuem sequências repetitivas de instruções. Por exemplo, o algoritmo da média de quatro avaliações:

Inicio
  real m1, m2, m3, m4
  real media

  escrever "Avaliação 1:"
  Ler m1
  escrever "Avaliação 2:"
  Ler m2
  escrever "Avaliação 3:"
  Ler m3
  escrever "Avaliação 4:"
  Ler m4

  media <- (m1 + m2 + m3 + m4) / 4

  escrever "Média: ", media
Fim

O algoritmo acima repete quatro vezes a sequência que lê uma nota do teclado. Porém há uma forma de expressar a repetição de sequências de instruções, usando-se o que se chama de estrutura de repetição. A estrutura de repetição enquanto condição faz repete todas as instruções enquanto a condição for verdadeira. A condição é escrita como uma expressão lógica, da mesma forma que na estrutura de decisão se condição então ... senão. Veja como fica o algoritmo acima ao ser reescrito para usar essa estrutura de repetição:

Inicio
  constante inteiro NUMEROS <- 4
  real m
  real media <- 0
  inteiro contador <- 0

  enquanto contador < NUMEROS faz  
    escrever "Avaliação ", contador, ":"
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

  escrever "Média: ", media/NUMEROS
Fim

Esse algoritmo funciona somente para médias de quatro números. Porém calcular a média de qualquer quantidade de números usa a mesma lógica: ler os números, somá-los e dividir o total pela quantidade de números lidos. Por exemplo, para fazer com que ele calcule a média de 7 números é necessário escrevê-lo assim:

Inicio
  constante inteiro NUMEROS <- 7
  real m
  real media
  inteiro contador <- 0

  enquanto contador < NUMEROS faz  
    escrever "Avaliação ", contador, ":"
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

  escrever "Média: ", media/NUMEROS
Fim

Note que o algoritmo praticamente não foi modificado, pois somente se alterou o valor da constante NUMEROS.

Esses dois algoritmos podem também ser visualizados como fluxogramas, como mostrado na figura abaixo:

Ex-repeticao.png

A estrutura de repetição junto com a sequência de instruções a ser repetida é comumente chamada de 'laço. No fluxograma acima o laço está destacado em vermelho, e no algoritmo em Portugol o laço aparece em:

  enquanto contador < NUMEROS faz  
    escrever "Avaliação ", contador, ":"
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

Um outro exemplo ainda mais simples é mostrar na tela uma contagem numérica:

inicio
    inteiro contador
    contador <- 0

    enquanto contador < 10 faz
        escrever contador , " "
        contador <- contador + 1
    fimenquanto
fim

Ao executar esse algoritmo, tem-se como resultado:

0 1 2 3 4 5 6 7 8 9

Seu fluxograma está mostrado a seguir:

Flux-Contagem.png


Repare no uso de uma variável auxiliar contador para controlar a quantidade de repetições. Essa é uma técnica comum para controlar a estrutura de repetição, e já foi usada no exemplo da média. Ela pode também ser combinada com outras condições, como mostrado abaixo:

inicio
    inteiro contador <- 1
    caracter opcao <- "s"
        
    enquanto ((opcao = "s") ou (opcao = "S")) e contador < 11 faz
        escrever contador, "\n"
        contador <- contador + 1
        
        escrever "\nContinuar (S/N) ? "
        ler opcao
    fimenquanto
    
    escrever "Terminou com contador = " , contador
fim

Nesse exemplo se usa um laço para mostrar uma contagem de 1 a 10. Porém há a possibilidade de encerrar o algoritmo. Observe a condição para continuidade do laço: ela é verdadeira somente se contador < 11 e se a variável opcao for igual a "s" ou "S".

Finalmente, apesar de ser comum o uso de contadores para controle do laço, pode-se usar qualquer condição para essa finalidade. Então podem existir laços que não usam contadores para controlar a quantidade de repetições, como no próximo exemplo:

inicio
    constante texto segredo <- "secreto"
    texto senha
    
    ler senha
    enquanto senha =/= segredo faz
        escrever "Voce continua preso ! Digite a senha correta: "
        ler senha
    fimenquanto
    escrever "Voce foi liberado ..."
fim

O fluxograma desse algoritmo segue abaixo:

Flux-Senha.png

Atividades

  1. Escreva um algoritmo que mostre a tabuada de um número fornecido pelo teclado. Esse número deve estar entre 1 e 10.
  2. Aproveite o algoritmo anterior para mostrar a tabuada de todos os números entre 1 e 10.
  3. Modifique o exemplo da média para que a quantidade de números a serem lidos seja previamente informada pelo teclado.
  4. Escreva algoritmos que mostrem as seguintes sequências de números:
    • Números pares menores que 100
    • Números ímpares menores que 100
    • Números pares de 100 até 4 (contagem decrescente)
    • Múltiplos de 3 menores que 100
    • Múltiplos de 4 e múltiplos de 5 menores que 100
    • Múltiplos comuns menores que 1000 de dois números fornecidos pelo teclado (ex: se forem fornecidos 6 e 8, deve aparecer 24, 48, 72, ...)
  5. Modifique novamente o exemplo da média para que ela funcione para um quantidade de números desconhecida de antemão. Quer dizer, o algoritmo deve ler os números para calcular a média, mas não sabe quantos números existem (e isto não pode ser informado pelo teclado).
  6. Modifique o exemplo da senha para que o usuário tenha somente três tentativas permitidas para digitar a senha correta. Caso ao final as três senhas estejam erradas, o algoritmo deve informar que a conta foi bloqueada.
  7. Escreva um algoritmo que leia até 10 números do teclado, e informe ao final qual o maior e o menor deles.
  8. Escreva um algoritmo que teste se um número informado pelo teclado é primo.
  9. Aproveite o algoritmo do ítem anterior para mostrar todos os números primos menores que 1000.
  10. Usando o algoritmo de teste de número primo, faça um novo algoritmo que fatore um número. Ex: a fatoração do número 15 resulta em 3 e 5 (3 X 5), e a fatoração de 54 resulta em 2, 3, 3 e 3 (2 X 3 X 3 X 3).
  11. Usando estrutura de repetição, escreva um algoritmo que converta um número de decimal para binário. Assuma um número binário com 16 bits.
  12. Escreva um algoritmo para calcular o MMC (Mínimo Múltiplo Comum) de dois números. O MMC de dois números é um número que pode ser dividido por qualquer um deles sem deixar resto. Ex:
    • MMC de 8 e 6 = 24
    • MMC de 3 e 5 = 15
    • MMC de 3 e 27 = 27
  13. Escreva um algoritmo para calcular o MDC (Máximo Divisor Comum) de dois números. O MDC de dois números é um número capaz de dividi-los sem deixar resto. Ex:
    • MDC de 24 e 16 = 8
    • MDC de 5 e 3 = 1
    • MDC de 60 e 150 = 30
  14. Faça um algoritmo para descobrir os dois maiores números dentre 6 números lidos do teclado.
  15. Faça um algoritmo para converter um número entre 0 e 16777215 para sua representação em hexadecimal.
  16. Escreva o algoritmo para uma calculadora aritmética (operações +, -, * e /) que lê continuamente do teclado números e operadores. A calculadora deve ler continuamente uma sequência do tipo número operador_aritmético, até que o operador informado seja =, quando então o resultado da conta deve ser mostrado na tela. Ex:
    • 1 + 2 * 5 / 3 = 5
    • 2 * 5 - 1 / 3 = 3

04/10: Estruturas de repetição

Resolução de exercícios

05/10: Estruturas de repetição

Resolução de exercícios

18/10: Estruturas de repetição

Para variavel de inicio ate fim passo incremento

Há casos em que se deseja repetir uma parte de um algoritmo certo número de vezes. Para esses casos há uma estrutura mais prática que enquanto condição faz:

inicio
  inteiro i
  inteiro v[5]

  escrever "Digite 5 números: \n"

  para i de 0 ate 4 passo 1
    escrever "Numero ", i, ": "
    ler v[i]
  proximo

  escrever "\nOs numeros em ordem inversa são:\n\n"

  para i de 4 ate 0 passo -1
    escrever "Numero ", i, ": ", v[i], "\n"
  proximo

fim

Atividades

  1. Escreva o algoritmo para comparar dois vetores, porém usando a estrutura para.
  2. Escreva um algoritmo para procurar se um vetor menor (com menos valores) está contido em um vetor maior. Caso afirmativo, mostre a partir de que posição ele aparece. Assuma vetores de números inteiros.
  3. Modifique o algoritmo acima para mostrar todas as ocorrências do vetor menor dentro do maior.
  4. Modifique o algoritmo do anterior para remover todas as ocorrências do vetor menor dentro do maior.
  5. Resolva o problema do bingo usando a estrutura para

19/10: Estruturas de repetição

Variáveis multidimensionais

Em matemática existem matrizes e vetores, que são variáveis multidimensionais. Por exemplo, uma matriz 3 x 3 (3 linhas e 3 colunas) pode ser:

Vetores são matrizes unidimensionais, portanto possuem somente uma linha ou uma coluna:

Cada elemento em uma matriz ou vetor é identificado pela sua posição. Por exemplo, na posição 1, 2 da matriz A acima está o valor 6, e na posição 4 do vetor v está o valor 18. Assim, a matriz A do exemplo pode ser entendida da seguinte forma:

... e o vetor v do exemplo:

Nas linguagens de programação em geral existe um conceito muito parecido, chamado de variáveis multidimensionais ou simplesmente matrizes (arrays em inglẽs). Para exemplificar, no Portugol se poderiam definir a matriz A e o vetor v:

inicio
  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro M[3][2]
  inteiro v[5] <- {1, 6, 2, 18, 5}

  escrever "Valor de A[0][0]: ", A[0][0], "\n"
  escrever "Valor de A[0][1]: ", A[0][1], "\n"
  escrever "Valor de A[1][0]: ", A[1][0], "\n"
  escrever "Valor de A[1][1]: ", A[1][1], "\n"

  escrever "Valor de v[0]: ", v[0], "\n"
  escrever "Valor de v[1]: ", v[1], "\n"
  escrever "Valor de v[2]: ", v[2], "\n"
  escrever "Valor de v[3]: ", v[3], "\n"
  escrever "Valor de v[4]: ", v[4], "\n"

fim

A declaração da matriz se faz como uma variável comum, porém indicando-se suas dimensões:

  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro M[3][2];

Veja que a matriz M foi declarada sem valores iniciais, porém a matriz A foi inicializada na declaração.

O acesso aos elementos da matriz se faz usando-se índices, que funcionam como coordenadas dos elementos que se quer acessar. Os índices iniciam em 0:

  # índice 0,0
  escrever "Valor de A[0][0]: ", A[0][0], "\n"

O exemplo acima pode ser reescrito usando-se estruturas de repetição:

inicio
  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro v[5] <- {1, 6, 2, 18, 5}
  inteiro i, j

  enquanto i < 2 faz
    j <- 0
    enquanto j < 2 faz
       escrever "Valor do elemento de A na posição ", i, ", ", j, ": ", A[i][j], "\n"
       j <- j + 1
    fimenquanto
    i <- i + 1
  fimenquanto

  i <- 0
  enquanto i < 5 faz
    escrever "valor de v na posição ", i, ": ", v[i], "\n"
    i <- i + 1
  fimenquanto

fim

Como se vê, matrizes e vetores casam perfeitamente com estruturas de repetição, e são úteis para a resolução de inúmeros problemas. Por exemplo, o problema de mostrar o nome do mês a partir do número do mês, feito anteriormente com escolhe ... caso pode ser feito assim com um vetor:

inicio
  texto nome_mes[12] <- {"Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho",
                         "Julho", "Agosto", "Setembro", "Outubro", "Novembro",
                         "Dezembro"}
  inteiro dia, mes, ano

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  escrever dia, " de ", nome_mes[mes - 1], " de ", ano
fim

Outro problema comum é precisar guardar um conjunto de valores, e depois ordená-los:

inicio
  inteiro v[10]
  inteiro i
  inteiro quantidade

  escrever "Quantos valores serão digitados (máximo = 10) ? "
  ler quantidade

  i <- 0
  enquanto i < quantidade faz
    escrever "valor ", i, ": "
    ler v[i]
    i <- i + 1
  fimenquanto

  // ordena os valores ...

  escrever "valores ordenados: "
  i <- 0
  enquanto i < quantidade
    escrever v[i], " "
    i <- i + 1
  fimenquanto
fim

Atividades

  1. Escreva um algoritmo que leia 5 números do teclado, e depois mostre-os em ordem inversa à que foi digitada.
  2. Escreva um algoritmo que leia dois vetores de 5 números, e depois mostre se os vetores são iguais.

    Solução vista em aula:
    inicio
      inteiro v1[5]
      inteiro v2[5]
      inteiro n
    
      // Le os valores do primeiro vetor
      para n de 0 ate 4 passo 1
        escrever "v1[", n, "]: "
        ler v1[n]
      proximo
    
      // Le os valores do segundo vetor
      para n de 0 ate 4 passo 1
        escrever "v2[", n, "]: "
        ler v1[n]
      proximo
    
      // compara os dois vetores
      n <- 0
      enquanto n < 5 E v1[n] = v2[n] faz
        n <- n + 1
      fimenquanto
    
      // mostra o resultado da comparação
      se n = 5 entao
        escrever "Vetores iguais"
      senao
        escrever "Vetores diferem na posicao ", n
      fimse
    fim
    
  1. Escreva um algoritmo que leia um palavra do teclado e depois procure-a numa lista de palavras preexistente. Essa lista deve ser implementada usando um vetor.
  2. Escreva um algoritmo que leia 5 números, e mostre-os em ordem crescente.
  3. Modifique o algoritmo anterior para mostrá-los em ordem decrescente.
  4. Em um jogo de bingo devem-se contar quantos números de uma aposta foram sorteados no bingo. Faça um algoritmo que, dados os números sorteados e uma aposta, conta quantos números apostados foram sorteados.

25/10: 2a avaliação

Avaliação em aula, no laboratório de Redes. Resolver usando o Portugol. Compactar os arquivos com os algoritmos e entregar para o professor.

Obs: para compactar:

tar czf prova2-seu_nome.tgz *.alg

Você precisará instalar o Portugol em seu computador.

1) Contador de moedas: faça um programa que leia valores de moedas e some as quantidades de tipos de moedas informadas. Por exemplo, se o usuário digitar 25, 50, 25, 5, 10, 5, o programa deve informar: 2 moedas de 5 centavos, 1 moeda de 10 centavos, 2 moedas de 25 centavos, 1 moeda de 50 centavos. São aceitos apenas valores de moedas de 1, 5, 10, 25 e 50 centavos. Seu programa deve ler 10 valores de moedas, e então apresentar o resultado.

2) Calculadora de troco: escreva um programa que calcule o troco a ser devolvido a um cliente. O troco deve ser composto de notas de 50, 20, 10, 5, 2 ou 1 real, e também moedas de 1, 5, 10, 25 ou 50 centavos. Dê preferência ao uso de notas e moedas de maior valor. Por exemplo, se o troco a ser devolvido for R$ 17,75, seu programa deve informar 1 nota de R$ 10, 1 nota de R$ 5, 1 nota de R$ 2, 1 moeda de R$ 0,50, 1 moeda de R$ 0,25.

Inicio
  inteiro notas[6] <- {50,20,10,5,2,1}
  inteiro moedas[5] <- {50,25,10,5,1}
  inteiro reais, centavos
  inteiro i, aux
  
  escrever "Reais: "
  ler reais
  escrever "Centavos: "
  ler centavos
  
  para i de 0 ate 5 passo 1
    aux <- reais / notas[i]
    se aux > 0 entao
      escrever aux, " notas de R$ ", notas[i], "\n"
      reais <- reais % notas[i]
    fimse
  proximo
  
  para i de 0 ate 4 passo 1
    aux <- centavos / moedas[i]
    se aux > 0 entao
      escrever aux, " moedas de R$ 0,", moedas[i], "\n"
      centavos <- centavos % moedas[i]
    fimse
  proximo
  
fim

3) Modificação de senha: Para modificar uma senha deve-se primeiro fornecer a senha atual, e então a nova senha. É necessário escrever duas vezes a nova senha para confirmá-la. Escreva um algoritmo que modifique uma senha predefinida (no seu programa ela pode estar guardada em uma variável), seguindo essa regra de mudança de senha.

4) Nota de uma prova olímpica: um atleta de saltos ornamentais tem seu salto avaliado por 6 juízes. Após descartar a maior e a menor nota, calcula-se a média aritmética das notas dadas. Faça um programa que calcule a nota de um atleta.

Conceitos da 2a avaliação

Legenda:

  • T: Atendeu a questão totalmente
  • P: Atendeu parcialmente
  • N: Não atendeu
  • Sufixo +: apresentou uma boa solução
  • Sufixo -: apresentou uma solução que não escolheu estruturas de controle mais adequadas


Aluno Questão 1 Questão 2 Questão 3 Questão 4 Conceito
Fernando N N T- (testes redundantes da senha atual) T C
Gabriel D (ausente)
Levi D (ausente)
Lindalvo T (faltou testar se a moeda é válida) N T T A
Marcos T- (faltou testar se a moeda é válida, algoritmo muito extenso ...) N T N C
Marine T+ T T N A
Mario Allan T N T (algoritmo nunca termina !) N C
Mário André T (faltou testar se a moeda é válida) T T+ N A
Mário Sérgio N N N N D
Maykon T- (erro no teste de moeda válida) N T N (não identificou maior e menor notas) C
Nathany N N T T- (não identifica a menor nota) C
Pamella D (ausente)
Paulo Igor T- (não mostra moedas de 1 centavo, lê 11 moedas) N N N D
Ricardo N N P (não confere a senha atual) N D
Roberto D (ausente)
Thiago Martins D (ausente)
Thiago Ramos N N N N D
Vinicius Kachniacz N N N N D
Vinicius Rodrigues N N N (não confere as senhas) N (não exclui maior e menor notas) D

Linguagem C: Projeto final

26/10: Introdução à linguagem C

Obs: durante as aulas usaremos o NetBeans, um Ambiente Integrado de Desenvolvimento (IDE - Integrated Development Environment). Um IDE é um programa que auxilia o programador. Ele integra um editor de programas, um gerenciador de projetos, compilador e um depurador (debugger).

Para instalar o Netbeans:

  1. Faça o download do instalador. Salve-o em algum subdiretório.
  2. Abrindo um terminal, entre no subdiretório onde está o instalador e execute esse comando:
    bash netbeans-6.8-ml-cpp-linux.sh
    
    • Caso o instalador falhe porque não encontrou a JVM (Máquina Virtual Java), instale-a com esse comando:
      sudo apt-get install -y sun-java6-jdk
      
  3. Aceite as opções de instalação sugeridas pelo instalador.
  4. Ao final da instalação, o Netbeans 6.8 estará acessível pelo menu Aplicativos -> Programação.
  5. Sempre que for escrever um novo programa com o Netbeans, crie um novo projeto (ver menu Arquivo->Novo Projeto). Selecione um projeto do tipo "Aplicativo C/C++".

Compilando o primeiro programa

  • O clássico Hello World!
#include <stdio.h>

int main(int argc, char *argv[])
{
	printf("Alô mundo!\n");
}
  • Mostrando mensagens de na tela: puts e printf:
    #include <stdio.h>
    
    int main() {
      int n;
    
      n = 5;
      
      puts("Demonstração de puts e printf");
    
      printf("Valor de n: %d\n", n);
    
      n = n + 1;
    
      printf("Novo valor de n: %d\n", n);
    
      return 0;
    }
    
  • Lendo dados do teclado: scanf
    #include <stdio.h>
    
    int main() {
      int n;
    
      printf("Digite um número inteiro: ");
    
      scanf("%d", &n);
    
      printf("Valor digitado foi %d\n", n);
    
      return 0;
    }
    

Tipos de dados

Portugol C Exemplo
inteiro int int x;
caracter char char letra;
real float ou double float pi = 3.1416;
texto char * ou vetor de char char * mensagem = "Hello world";
char palavra[16];
logico qualquer tipo (valor 0 = Falso, qualquer outro valor = Verdadeiro) int ok = 1;
char teste = 0;


Comandos/funções e Estruturas de controle

Portugol C Exemplo
inteiro n, m

escrever "Ola, mundo!\n"
escrever "valor de n: ", n, "\n"
escrever "valor de n: ", n, ", e valor de x: ", x, "\n"
int n, m;

printf("Ola, mundo!\n");
printf("valor de n: %d\n", n);
printf("valor de n: %d, e valor de x: %d\n", n, x);
inteiro n

ler n
int n;

scanf("%d", &n);
se condição então
//comandos
fimse
if (condição) {
//comandos
}
se condição então
  //comandos
senão
  //comandos
fimse
if (condição) {
 //comandos
} else {
 //comandos
}
escolhe expressão
  caso valor1:  
    //comandos
  caso valor2:
    //comandos
  defeito:
    //comandos
fimescolhe
switch (expressão) {
  case valor1:
    //comandos
  case valor2:
    //comandos
  default:
    //comandos
}
enquanto condição faz
//comandos
fimenquanto
while (condição) {
  //comandos
}
para variavel de inicio ate fim passo incremento
//comandos
proximo
for (variavel=inicio; variavel <= fim; variavel++) {
//comandos
}

Atividades

  • Traduza para C os seguintes algoritmos Portugol:
    1. Inicio
        inteiro x, y
       
        Escrever "Digite um numero: ",
        Ler x
        Escrever "Digite outro numero: ",
        Ler y
        Escrever "Soma = ", x+y
      Fim
      
    2. Inicio
        inteiro x, y, z
       
        Escrever "Digite um numero: ",
        Ler x
        Escrever "Digite outro numero: ",
        Ler y
        z <- x + y
        Escrever "Soma = ", z
      Fim
      
    3. Inicio
        Inteiro n1, n2, n3, r
       
        Escrever "Primeiro numero: "
        ler n1
        Escrever "Segundo numero: "
        ler n2
        Escrever "Terceiro numero: "
        ler n3
       
        r <- (n1 + n2 + n3) /3
       
        Escrever "Media=", r
      Fim
      
    4. Inicio
        inteiro anos, dias
       
        Escrever "Quantos anos se passaram ? "
        Ler anos
        dias <- anos * 365
        Escrever "... então se passaram ", dias, " dias"
      Fim
      
    5. Inicio
        constante inteiro diasPorAno <- 365
        inteiro anos, dias
       
        Escrever "Quantos anos se passaram ? "
        Ler anos
        dias <- anos * diasPorAno
        Escrever "... então se passaram ", dias, " dias"
      Fim
      
    6. inicio
        real massa
        real forca
        real aceleracao
        constante real g <- 9.8
        constante real ac <- 0.01
        
        escrever "força: "
        ler forca
        
        escrever "massa: "
        ler massa
        
        aceleracao <- forca/massa - ac*massa*g
        
        escrever "aceleracao=", aceleracao, " m/s2"
        
      fim
      
    7. inicio
        real a, b, c
        real delta
        real x1, x2
        
        escrever "Forneça os coeficientes da equação de 2o grau (formato: ax^2 + bx + c):\n"
        escrever "a="
        ler a
        escrever "b="
        ler b
        escrever "c="
        ler c
        
        delta <- b^2 - 4*a*c
        x1 <- (-b + delta^0.5)/(2*a)
        x2 <- (-b - delta^0.5)/(2*a)
        
        escrever "1a raiz=", x1
        escrever "\n2a raiz=", x2  
      fim
      
    8. inicio
            real x1, x2, x3, x4, x5
            real media
            real desvioPadrao
            constante inteiro N <- 5
            
            // Ler os cinco valores pelo teclado
            ler x1
            ler x2
            ler x3
            ler x4
            ler x5
            
            // Calcular a media
            media <- (x1 + x2 + x3 + x4 + x5) / N
            
            // Calcular o desvio padrao
            desvioPadrao <- (x1 - media)^2 + (x2 - media)^2 + (x3 - media)^2 + (x4 - media)^2 + (x5 - media)^2
            desvioPadrao <- (desvioPadrao / (N-1))^0.5
            
            escrever "Media=", media
            escrever "\nDesvio padrao=", desvioPadrao
      fim
      
    9. inicio
            real renda
            real irpf
            
            escrever "Informe sua renda: "
            ler renda
            
            se renda < 1372.81 entao
              irpf <- 0
            senao 
              se renda < 2743.25 entao
                irpf <- (renda - 205.92)*0.15 
              senao
                irpf <- (renda - 548.82)*0.275
              fimSe
            fimSe
            
            escrever "Imposto devido: ", irpf  
      fim
      
    10. inicio
          inteiro dividendo
          inteiro divisor
          inteiro resto , quociente
      
          escrever "Dividendo: "
          ler dividendo
          escrever "Divisor: "
          ler divisor
      
          se divisor = 0 entao
              escrever "Nao pode dividir: divisor = 0 !!!"
          senao
              resto <- dividendo % divisor
              se resto = 0 entao
                  quociente <- dividendo / divisor
                  escrever dividendo , " / " , divisor , " = " , quociente
              senao
                  escrever "Nao pode fazer divisao inteira"
                  escrever " (resto = " , resto , ")"
              fimse
          fimse
      fim
      
    11. inicio
          inteiro termometro , barometro , tempo
      
          escrever "Qual a condição do termômetro: \n"
          escrever "Digite 1 para baixando , 2 para estacionário e 3 para subindo. \n"
          ler termometro
      
          escrever "Informe a condição do barômetro: \n"
          escrever "Digite 1 para baixando , 2 para estacionário e 3 para subindo. \n"
          ler barometro
      
          tempo <- termometro*10 + barometro
      
          escolhe tempo
              caso 11:
                  escrever "Chuvas abundantes e ventos de sul a sudoeste fortes"
              caso 12:
                  escrever "Chuva Provavel , ventos de sul a sudeste"
              caso 13:
                  escrever "Tempos Bons , ventos de sul a sudeste"
              caso 21:
                  escrever "Frente quente com chuva provavel"
              caso 22:
                  escrever "Tempo Incerto , ventos variaveis"
              caso 23:
                  escrever "Tempos Bons , ventos do leste frescos"
              caso 31:
                  escrever " Tempo instavel , aproximaçao de frente"
              caso 32:
                  escrever "Tempo Mudando para bom , ventos de leste"
              caso 33:
                  escrever "Tempos Bons , ventos quentes e secos"
              defeito:
                  escrever "Utilize somente os algorismos de 1 a 3 para indicar as condiçoes do equipamentos"
          fimescolhe
      fim
      
    12. inicio
          // coeficientes do polinomio  [ax^2 + bx + c = 0 ]
          real a , b , c
          
          escrever "Forneça os coeficientes da equação de 2o grau:\n"
          escrever "a="
          ler a
          escrever "b="
          ler b
          escrever "c="
          ler c
          
          // equação do tipo [ bx + c = 0 ]
          se a = 0 entao
              escrever " não é uma equação de 2o grau !!!"
          senao
              // calcular o delta => interior da raiz
              real delta
              
              delta <- b ^ 2 - 4 * a * c
              
              // não existem raizes  reais de números negativos
              se delta < 0 entao
                  escrever " não tem raizes reais"
              senao
                  // -----------  raiz dupla  ----------------
                  se delta = 0 entao
                      real x1
                      x1 <- -b / 2 * a
                      escrever "\nraiz dupla : " , x1
                  senao
                      // - ---------- duas raizes ---------------
                      real x1 , x2
                      x1 <- ( -b + raiz ( delta ) ) / 2 * a
                      x2 <- ( -b - raiz ( delta ) ) / 2 * a
                      escrever "\nraiz x1 : " , x1
                      escrever "\nraiz x2 : " , x2
                  fimse//raiz dupla
              fimse// delta >0
          fimse// a <> 0
      fim
      
    13. inicio
          inteiro num, bit
          inteiro base
          
          escrever "Este algoritmo converte um número inteiro para sua representação binária.\n"
          Escrever "O número deve estar entre 0 e 131071, e a representação binária\n"
          escrever "terá 17 bits\n\n"
          escrever "Digite o numero a ser convertido para binário: "
          ler num
      
          base <- 65536
          enquanto base > 0 faz
              bit <- ( num / base ) % 2
              escrever bit, " " 
              base <- base / 2
          fimenquanto
      fim
      
    14. inicio
          inteiro n , fat
          ler n
          fat <- 1
          enquanto n > 1 faz
             fat <- fat * n
             n <- n - 1         
          fimenquanto
          
          escrever "Fatorial=" , fat
      fim
      
    15. inicio
          inteiro valor , menor , contador
          ler menor
          contador <- 9
          enquanto contador > 0 faz
              ler valor
              se valor < menor entao
                  menor <- valor
              fimse
              contador <- contador - 1
          fimenquanto
          escrever "menor valor = ", menor
      fim
      
    16. inicio
          inteiro numero , n , resto <- 1
          escrever "Forneçaa um número: "
          ler numero
          n <- 2
          enquanto n <= numero / 2 e resto =/= 0 faz
              resto <- numero % n
              escrever "n=" , n , ": resto=" , resto , "\n"
              n <- n + 1
          fimenquanto
          
          se resto = 0 entao
              escrever "nao primo: divisivel por " , n - 1
          senao
              escrever "primo"
          fimse
      fim
      
    17. // Le 5 valores e identifica os dois maiores.
      inicio
          inteiro valor , maior1 , maior2 , contador
          
          ler valor
          maior1 <- valor
          
          ler valor
          se valor > maior1 entao
            maior2 <- maior1
            maior1 <- valor
          senao
            maior2 <- valor
          fimse
      
          contador <- 3
          enquanto contador > 0 faz
              ler valor
              se valor > maior1 entao
                  maior2 <- maior1
                  maior1 <- valor
              senao
                  se valor > maior2 entao
                      maior2 <- valor
                  fimse
              fimse
              contador <- contador - 1
          fimenquanto
      
          escrever "maior valor = " , maior1
          escrever "\nsegundo maior valor = " , maior2
      fim
      

08/11: Começo do projeto

Para referência: apostila online sobre linguagem C.

O jogo: Campo Minado

O Campo Minado é um jogo clássico disponível em diferentes sistemas operacionais. Basicamente devem-se procurar as minas existentes em um campo quadriculado, perdendo-se o jogo se pisar em uma mina, e vencendo se descobrir todas as minas. O jogo oferece pistas sobre a localização das minas, e usando-se um pouco de lógica podem-se encontrá-las. Uma versão desse jogo para Linux aparece na figura a seguir .

Minas-linux.png

A cada jogada deve-se escolher uma casa do tabuleiro, optando-se por pisá-la (revelando-a) ou marcá-la como uma provável mina. Ao pisar numa casa, três ações podem ocorrer:

  1. A casa contém uma mina, o que revela todas as demais minas e encerra o jogo com derrota.
  2. A casa é vizinha a uma ou mais minas, e assim em seu lugar aparece o número de minas em casas vizinhas.
  3. Nenhuma mina existe em casas vizinhas, então a casa aparece vazia. Além disso, todas as casas vizinhas que também não possuam minas são reveladas.

Ao final do jogo, a pontuação é dada pelo tempo que se levou para se descobrirem as minas. O jogo contabiliza uma lista de melhores jogadas, contendo o nome do jogador e o tempo de jogo. Melhores jogadas são aquelas com menores tempos de jogo.

A versão do jogo a ser desenvolvida será baseada em texto (mas quem quiser fazer uma versão gráfica fique à vontade !). Basicamente deve ser apresentado o tabuleiro, mostrando-se apenas as casas já reveladas e o tempo de jogo decorrido, e um prompt pedindo as coordenadas da próxima casa assim como o tipo de ação (se pisar na casa ou marcar a provável existência de uma mina).

Etapas de desenvolvimento

  • Proposta de código que contempla:
    • Bibliotecas e definições
    • Declaração de constantes e variáveis
      • Uso de variáveis com mesmo nome e diferentes escopos
      • Vetor e matriz
    • Operadores lógicos e matemáticos
    • Expressões
      • E/S
      • Estruturas de decisão e repetição
    • Funções
      • Passagem de parâmetro por valor e por referência
    • Acesso a uma matriz através de um vetor linear (função iniciaJogo)
    • Ponteiros

O laço principal do jogo ...

O jogo funciona com um laço principal, que lê as coordenadas da pŕoxima casa e a ação a ser feita, e atualiza o tabuleiro apropriadamente:

Fluxo-Campo-Minado.png

Note que nesse laço devem-se contabilizar quantas minas fora descobertas. Esse valor é necessário para decidir se o jogo já acabou.

O tabuleiro

Representar o tabuleiro: etapas X a Y.

O tabuleiro do campo minado deve ser representado em formato de texto conforme a figura abaixo. Nesta figura, o tabuleiro está completamente revelado.


Tabuleiro-Minado.png


As colunas são identificadas por letras maiúsculas, e as linhas por números. Cada casa do tabuleiro pode conter uma mina ou um número que conta quantas minas existem em casas vizinhas. Casas já reveladas devem mostrar essa contagem de minas vizinhas, sendo que se não houver minas a casa deve ser mostrada vazia (preenchida com espaço). Casa em que se marcou a existência de uma mina deve mostrar a letra M. Por fim, casas ainda não reveladas devem ser preenchidas com o caractere ?. Um tabuleiro parcialmente revelado apareceria como a figura abaixo.


Tabuleiro-Minado2.png


Etapa 1: Modelando o tabuleiro

Conteúdos abordados:

Deve-se nessa etapa escolher uma forma de representar o tabuleiro dentro do programa. Devem-se pensar também em como representar as casas do campo minado:

  • Como definir que uma casa possui uma mina ?
  • Como definir que uma casa está vazia ? Nesse caso, como informar a quantidade de minas em casas vizinhas ?
  • Como definir se uma casa já foi pisada ?

Ponto de partida para mostrar um tabuleiro na tela. O tabuleiro foi modelado como uma matriz de inteiros bidimensional.

#include <stdio.h>

int main(int argc, char** argv) {
    int tabuleiro[5][5] = { {0,0,1,1,0}, {1,1,2,0,0}, {10,1,0,0,0},
                           {1,1,1,0,0}, {0,0,0,0,10} };
    int i, j;

    //i indica a linha, j a coluna
    i = 0;
    while (i < 5) {
        // O while abaixo mostra todas as colunas da linha "i"
        j = 0;
        while (j < 5) {
            printf("%d ", tabuleiro[i][j]);
            j++;
        }

        printf("\n");
        i++;
    }

    return (EXIT_SUCCESS);
}

Cada casa dessa matriz contém um número inteiro. Para representar o estado de cada casa do tabuleiro sugeriu-se um código numérico:

  • Casa com mina: algum número > 8
  • Casa sem mina: um número que conte quantas minas existem em casas vizinhas. Tal número estará entre 0 e 8.


09/11: O tabuleiro

Conteúdos abordados:

Desenhando o tabuleiro completo

Dando continuidade à visualização do tabuleiro, agora deve-se desenhá-lo por completo na tela. Quer dizer, mostrar um tabuleiro com 10 linhas e 10 colunas, seguindo a abordagem da aula anterior.

Para mostrar o tabuleiro, deve-se explorar o uso da função printf, que serve para mostrar dados na tela.

Zerando o tabuleiro

Fluxograma do algoritmo que zera o tabuleiro:

Zera-tabuleiro.png


... e esse fluxograma traduzido para linguagem C:

    // Zerar todas as posições do tabuleiro !
    i = 0;
    while ( i < LINHAS) {
        j = 0;
        while (j < COLUNAS) {
            tabuleiro[i][j] = 0;
            j++;
        }
        i++;
    }

Colocando as minas

No tabuleiro devem ser colocadas 10 minas aleatoriamente. Isso significa que para cada uma dessas minas, devem-se gerar aleatoriamente suas coordenadas no tabuleiro. A geração de números aleatórios pode ser feita usando-se a função random(). Essa função gera um número inteiro entre 0 e 2147483647. Para usá-la no tabuleiro, pode-se fazer o seguinte:

#include <stdlib.h>

int main() {
  int x, y;

  // gera dois números aleatórios entre 0 e 9, e guarda-os nas variáveis x e y
  x = random() % 10;
  y = random() % 10;
  
}

A versão atual do jogo está assim:

#include <stdio.h>
#include <stdlib.h>

#define MINAS 10
#define LINHAS 10
#define COLUNAS 10

#define TEM_MINA 10

/*
 * 
 */
int main(int argc, char** argv) {
    int tabuleiro[LINHAS][COLUNAS];
    int i, j;

    // Zerar todas as posições do tabuleiro !
    i = 0;
    while ( i < LINHAS) {
        j = 0;
        while (j < COLUNAS) {
            tabuleiro[i][j] = 0;
            j++;
        }
        i++;
    }
    
    // Colocar as minas aqui !!!

    //Agora mostrar o tabuleiro que foi gerado

    //i indica a linha, j a coluna
    i = 0;
    while (i < LINHAS) {
        // O while abaixo mostra todas as colunas da linha "i"
        j = 0;
        while (j < COLUNAS) {
            if (tabuleiro[i][j] == TEM_MINA) {
                printf("* ");
            } else {
                if (tabuleiro[i][j] == 0) {
                    printf("  ");
                } else {
                    if ((tabuleiro[i][j] >= 1) && (tabuleiro[i][j] <= 8)) {
                        printf("%d ", tabuleiro[i][j]);
                    }
                }
            }
            j++;
        }

        printf("\n");
        i++;
    }

    return (EXIT_SUCCESS);
}

Meta desta semana

Nesta semana o seu programa deve ser capaz de:

  1. Representar o tabuleiro com uma matriz de inteiros bidimensional.
  2. Mostrar o tabuleiro na tela, indicando o que existe em cada casa. O tabuleiro deve ser apresentado enfeitado, o que significa que deve mostrar uma grade para separar as casas e a identificação de linhas e colunas. Linhas devem ser identificadas numericamente, e colunas devem ser identificadas por letras (ex: primeira coluna=A, segunda coluna=B, ...).
  3. Colocar minas aleatoriamente no tabuleiro.

O seu programa cumprindo as metas acima deve ser apresentado ao professor na próxima aula (16/11), já sendo parte da avaliação desta unidade.

16/11: As minas e o tabuleiro

Conteúdos abordados:

Dúvidas sobre random()

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

int main() {
  int x,y,z;
  time_t t;

  // Lê o valor do relógio
  t = time(NULL);

  // Usa o valor do relógio como semente do gerador de números
  // pseudo-aleatórios.
  srandom(t);

  // Sorteia três números pseudo-aleatórios
  x = random() % 10;
  y = random() % 10;
  z = random() % 10;

  printf("x=%d, y=%d, z=%d\n", x, y, z);
}

Funções

A função mostra_tabuleiro corresponde ao algoritmo para desenhar o tabuleiro na tela. O tabuleiro em si é representado pela variável tabuleiro, que tem escopo global (visível em todas as funções do programa). Neste momento é bom ler um pouco mais sobre funções na linguagem C:


Para fixar

  1. Escreva um programa para ler 10 números do teclado, e em seguida mostrar o maior e o menor número.
  2. Reescreva o programa anterior, mas criando as funções "maior" e "menor", que retornam o maior e menor número de um vetor de tamanho arbitrário.
  3. Faça um programa que desenhe a seguinte figura na tela (use uma função para desenhar cada linha):
        '
        *
       ***
      *****
     *******
    *********
     *******
      *****
       ***
        *
    
  4. Até que ponto se poderiam usar funções para mostrar o tabuleiro ? Imagine que mostrar o tabuleiro fosse uma tarefa composta por 2 subtarefas:
    1. Mostrar o estado de uma casa do tabuleiro
    2. Mostrar o tabuleiro completo: mostrar todas as casas (usa subtarefa anterior).
      Note que essas subtarefas correspondem à sequência do projeto até o momento. Um bom exercício seria modelar a tarefa de mostrar o tabuleiro usando uma função para cada subtarefa escrita acima.

22/11: Contando minas vizinhas

A contagem de minas

Para ajudar a visualizar o algoritmo de contagem de minas vizinhas, segue o fluxograma abaixo. As coordenadas (x,y) correspondem à casa cujas minas vizinhas se desejam contar. Veja sua semelhança com o algoritmo para zerar o tabuleiro.

Conta-minas.png

A sugestão é por o algoritmo de contagem em uma função, e dentro do programa chamá-lo para cada casa do tabuleiro:

#include <stdio.h>
#include <stdlib.h>

#define MINAS 10
#define LINHAS 10
#define COLUNAS 10

#define TEM_MINA 10

// O tabuleiro como variável global: necessário para poder ser usado e modificado por outras funções
int tabuleiro[LINHAS][COLUNAS];


// Função para contar as minas vizinhas da casa x, y
void conta(int x, int y) {

  
}

/*
 * 
 */
int main(int argc, char** argv) {
    int i, j;

    // Zerar todas as posições do tabuleiro !
    i = 0;
    while ( i < LINHAS) {
        j = 0;
        while (j < COLUNAS) {
            tabuleiro[i][j] = 0;
            j++;
        }
        i++;
    }
    
    // Colocar as minas aqui !!!

    // contar as minas vizinhas de cada casa do tabuleiro
    i = 0;
    while ( i < LINHAS) {
        j = 0;
        while (j < COLUNAS) {
            // chama a função de contagem de minas, para contar as minas
            // vizinhas da casa com coordenadas i,j
            conta(i, j);
            j++;
        }
        i++;
    }

    //Agora mostrar o tabuleiro que foi gerado

Obs: cuidado com o seguinte ao fazer o algoritmo de contagem de minas:

  • Casas na borda do tabuleiro possuem menos casas vizinhas (casas fora do tabuleiro devem ser ignoradas).
  • O algoritmo não pode ser aplicado em casas que contêm minas. Quer dizer, não faz sentido calcular as minas vizinhas de uma casa que tem uma mina.

Levando em conta as restrições acima, o algoritmo deve ficar parecido com o seguinte:

Conta-minas2.png

23/11: Pensando no jogo completo !

Topicos sobre linguagem C

Estrutura de repetição for

A estrutura de repetição for costuma ser mais usada por programadores do que while. Ao contrário de sua contraparte no Portugol (para variavel de inicio ate fim ...), a estrutura for possui grande flexibilidade para controle das repetições de um laço. Quer dizer, qualquer laço implementado com while pode ser também implementado com for. O diferencial do for está na possibilidade de concentrar todas as instruções necessárias para controlar o laço.

A estrutura for pode ser declarada da seguinte forma:

for (inicialização; condição; atualização) {
//comandos
}

... sendo:

  • inicialização: instruções a serem executadas no início do laço (antes da primeira repetição)
  • condição: condição (expressão lógica) para a continuidade do laço. Deve ser verdadeira para que se execute mais uma repetição.
  • atualização: instruções a serem executadas ao final de cada repetição

Por exemplo, para mostrar os números de 1 a 10 na tela:

  int x;

  for (x=1; x < 11; x++) {
    printf("x=%d\n", x);
  }

Veja no exemplo acima que tudo o que se precisa saber sobre o controle do laço está concentrado na declaração do for:

  for (x=1; x < 11; x++) {
  • inicialização (x=1): o laço inicia atribuindo o valor 1 à variável x
  • condição (x < 11): o laço continua enquanto o valor da variável x for menor que 11
  • atualização (x++): ao final de cada repetição, o valor da variável x é incrementado

Muitas possibilidades existem para o uso de for. Veja este outro exemplo:

  char c;

  for (c = 'A'; c < 'K'; c++) {
    printf("%c ", c);
  }


O programa do Campo Minado com o uso de for ao invés de while fica assim:

#include <stdio.h>
#include <stdlib.h>

#define MINAS 10
#define LINHAS 10
#define COLUNAS 10

/*
 * 
 */
int tabuleiro[LINHAS][COLUNAS];

void conta(int x, int y) {

}

int main(int argc, char** argv) {
    int i, j;

    // zerar todas as posições do tabuleiro !
    for (i=0; i < LINHAS; i++) {
        for (j=0; j < COLUNAS; j++) {
            tabuleiro[i][j] = 0;
        }
    }

    // Colocar as minas aqui !!!

    // Contar as minas vizinhas
    for (i=0; i < LINHAS; i++) {
        for (j=0; j < COLUNAS; j++) {
            conta(i,j);
        }
    }

    //Agora mostrar o tabuleiro que foi gerado

    //i indica a linha, j a coluna
    for (i=0; i < LINHAS; i++) {
        // O while abaixo mostra todas as colunas da linha "i"
      for (j=0; i < COLUNAS; j++) {
            if (tabuleiro[i][j] == 10) {
                printf("* ");
            } else {
                if (tabuleiro[i][j] == 0) {
                    printf("  ");
                } else {
                    if ((tabuleiro[i][j] >= 1) && (tabuleiro[i][j] <= 8)) {
                        printf("%d ", tabuleiro[i][j]);
                    }
                }
            }
        }
        printf("\n");
    }

    return (EXIT_SUCCESS);
}

Condições e operadores lógicos

Obs: cada condição em linguagem C deve ser envolvida por parênteses.

Necessários para expressar condições a serem usadas principalmente com if e while.

Portugol C Exemplo
E &&
if ((x >= 0) && (x <= 9)) {
  printf("coordenada x é válida\n");
}
OU ||
if ((x < 0) || (x > 9)) {
  printf("coordenada x é inválida\n");
}
NAO !
if (!((x < 0) || (x > 9))) {
  printf("coordenada x é válida\n");
}

Uma versão alternativa para a contagem de minas

A versão abaixo foi criada pela Marine e Nathany. Apesar de parecida com o algoritmo proposto pelo professor, possui uma diferença importante que a torna mais eficiente.

Conta-minas-nathany-marine.png

29/11: Pensando no jogo completo ...

  • Continuando funções: variáveis locais e globais, escopo de variáveis.

Escondendo as casas não pisadas

No momento você deve já conseguir mostrar todo o tabuleiro, porém no jogo apenas as casas já pisadas devem ser reveladas. Pense em como modelar o seu tabuleiro de forma a esconder as casas ainda não pisadas.

Opções:

  1. Criar uma matriz de controle: cada casa dessa nova matriz informa se a casa correspondente do tabuleiro está revelada. Por exemplo, se a casa (1,2) na matriz de controle tiver o valor 0 (zero), então a casa (1,2) do tabuleiro está escondida, e se tiver o valor 1, a casa (1,2) do tabuleiro está revelada.
  2. Explorar os códigos numéricos das casas: os códigos numéricos das casas do tabuleiro poderiam ser estendidos para informar se uma casa está escondida ou revelada. Por exemplo, se o código de uma casa for menor do que 100, ela está escondida, caso contrário está revelada. Assim, se casa (1,2) tiver o valor 3, significa que possui 3 minas vizinhas porém ainda está escondida, e se tiver o valor 103 significa que possui 3 minas vizinhas e já está revelada.

30/11: Pensando no jogo completo ...

Organizando o programa

Nesse momento seu programa deve estar ficando comprido, e já começando a se mostrar difícil de ler. Para torná-lo organizado e compreensível, deve ser reorganizado usando funções:

void inicia_tabuleiro() {
}

void mostra_tabuleiro(int tudo) {
}

int main() {
  // cria o tabuleiro, pondo as minas e contando as minas vizinhas de 
  // cada casa
  inicia_tabuleiro();
  
  // Mostra o tabuleiro que foi criado
  // O argumento da função serve para forçar a mostrar todas as casas
  // (mesmo as escondidas), ou mostrar somente as reveladas.
  // Se for 1, mostra todas as casas.
  // Se for 0, mostra somente as reveladas.
  mostra_tabuleiro(1);
}

Retomando o laço principal do jogo ...

Como apresentado na aula de 08/11, o jogo funciona com um laço principal, que lê as coordenadas da casa a ser pisada ou marcada e atualiza o tabuleiro apropriadamente:

Note que nesse laço devem-se contabilizar quantas minas foram realmente descobertas - o que não corresponde necessariamente a quantas minas foram marcadas ... A quantidade de minas descobertas é necessária para decidir se o jogo já acabou.

Fluxo-Campo-Minado.png

A leitura das coordenadas deve ser feita usando a função scanf.

Pisando e marcando casas

O jogador pode pisar em uma casa. Ao pisar em uma casa com mina, o jogador perde e o jogo acaba. Se pisar em uma casa com minas vizinhas, o jogo revela a contagem de minas vizinhas daquela casa. Mas se a casa pisada não tiver minas vizinhas, o jogo deve revelar todas as casas vizinhas na mesma condição, até o limite de casas que possuem minas vizinhas. Na figura abaixo, pisou-se na casa que está sob o ponteiro do mouse. Note que todas as casas ao redor também foram reveladas, até alcançarem-se casas que têm minas vizinhas.

Minas-pisadas.png

Pense em como abrir as casas vazias em torno da casa pisada ...

O jogador pode também marcar uma casa, indicando que acredita ter ali uma mina. Essa casa continua escondida, porém deve ser mostrado que possui uma bandeira, como mostrado na figura abaixo. Se o jogador descobrir todas as minas, o jogo termina com sua vitória. Como se podem representar essas bandeiras no tabuleiro ?

Casas-marcadas.png

06/12: Pensando no jogo completo ...

Uma vez criado o laço principal do jogo, em que se lêem coordenadas de casas a serem pisadas até que o jogo termine, faltam alguns refinamentos. São eles:

  1. Ao pisar numa casa que não possui minas vizinhas, devem-se abrir todas as casas adjacentes até encontrar casa que possuam minas vizinhas.
  2. Devem-se contabilizar as minas descobertas (casas marcadas), pois se todas as minas tiverem sido marcadas o jogo termina com vitória do jogador.

Abrindo casas que não possuem minas vizinhas

Ao se pisar em uma casa que não possui minas vizinhas, devem-se abrir recursivamente as casas adjacentes até encontrar casa com minas vizinhas. As figuras a seguir mostram como seria a abertura das casas (em vermelho a casa a ser aberta, e em hachurado as casas adjacentes):

Abre-1.png

Início: abrindo a casa pisada e testando as casas adjacentes


Abre-2.png
Aplicando a abertura de casa à cada casa adjacente


Abre-3.png
Novamente aplicando a abertura de casa às casas adjacentes ...


O algoritmo que faz essa abertura de casas pode ser expresso da seguinte forma (note a recorrência, quando o algoritmo chama si próprio):


Abre-casas.png

Mostrando o tempo decorrido

Para mostrar o tempo de jogo decorrido, devem-se contabilizar quantos segundos passaram desde que o jogo começou. Assim, deve-se ler o relógio do computador no início do jogo, e a cada vez que se precisar mostrar o tempo de jogo. Para ler o relógio pode-se usar a função time (já usada no algoritmo para colocar minas aleatoriamente). A contagem de quantos segundos se passaram se resume portanto a ler o relógio e subtrair o valor do relógio lido no início do programa, como no exemplo abaixo:

#include <time.h>
#include <stdio.h>

int main() {
  time_t inicio;
  time_t agora;

  inicio = time(NULL);

  // faz alguma coisa

  agora = time(NULL);

  printf("Já passaram %d segundos desde o inicio deste programa ...\n", agora - inicio);  
}

Além de contar o tempo de jogo decorrido, é necessário mostrá-lo em um formato claro para o jogador. Isso quer dizer, mostrar o tempo na forma "horas:minutos:segundos" ao invés de simplesmente a contagem de segundos. Por exemplo, se já transcorreram 143 segundos, deve-se mostrar "00:02:23". Para converter a contagem de segundos para esse formato você pode aproveitar o algoritmo de conversão de tempo proposto em um exercício de Lógica de Programação. Para formatar o horário como indicado, você pode conferir a explicação sobre printf.

Tópico sobre linguagem C: caracteres e strings

Caracteres (tipo de dados char) seguem a codificação ASCII.

Strings são o equivalente ao tipo Texto do Portugol.

Para fixar

  1. Faça um programa que mostre a tabela ASCII: cada caractere com seu correspondente código numérico.
  2. Escreva um programa que leia separadamente o nome e o sobrenome de uma pessoa, e em seguida mostre-os da seguinte forma na tela: sobrenome, nome.
  3. Escreva um programa para resolver a questão 2 da 2a avaliação.
  4. Escreva um programa que leia uma palavra do teclado, e em seguida mostre-a em ordem invertida.
  5. Faça um programa que leia uma palavra do teclado, e em seguida converta-a para maiúsculas.
  6. Faça um programa para ler uma frase do teclado, e contar quantas palavras nela existem.

07/12: Pensando no jogo completo

ATENÇÃO: preparar para apresentar o projeto na próxima 2a feira (13/12)


Tópicos em linguagem C: estruturas de dados (criação de novos tpos de dados)

13/12: Últimos ajustes ...

14/12: Apresentação

Na próxima semana, na 3a feira (14/12), vocês deverão apresentar os projetos sobre o campo minado. A apresentação será individual, em que entrevistarei cada aluno sobre sua participação no trabalho. Assim, se na entrevista for demonstrado que o aluno teve participação ativa no desenvolvimento do programa e domina o entendimento de como ele funciona, então receberá o conceito dado ao trabalho. Se não mostrar que entende como ele funciona, então ficará com conceito D e terá que fazer a prova de recuperação.

Para avaliar o trabalho, irei conferir se:

  1. O jogo funciona como especificado (ver laço principal do jogo na Wiki):
    1. O tabuleiro é criado e inicializado corretamente
    2. O tabuleiro é apresentado na tela conforme especificado na wiki (linhas como números e colunas como letras, grade, casas escondidas, reveladas ou marcadas com bandeiras)
    3. O programa lê as coordenadas de casas fornecidas pelo jogador, e executa corretamente a ação solicitada (pisar ou marcar), além de conferir se as coordenadas são válidas
    4. O jogo termina se uma mina for pisada, e nesse caso revelando todas as casas do tabuleiro
    5. O jogo termina se o jogador descobrir todas as minas: se as únicas casas não reveladas forem exatamente as casas com minas que podem estar marcadas ou não com bandeiras)
    6. Se ao pisar numa casa sem minas vizinhas, as casas adjacentes são reveladas recursivamente até encontrar casas que tenham minas vizinhas.
  2. O programa está organizado e estruturado com funções


Ítens extras, que são opcionais e aumentarão o conceito final da disciplina se forem feitos, são:

  • Mostrar o tempo de jogo decorrido sempre que for ler novas coordenadas do jogador (ver na wiki dicas de como fazer)
  • Ter níveis de dificuldade do jogo:
    • Fácil: tabuleiro 10 x 10 com 10 minas
    • Médio: tabuleiro 15 x 15 com 15 minas
    • Difícil: tabuleiro 20 x 20 com 30 minas

A prova de recuperação será dia 20/12 (2a feira), e terá ao menos quatro questões sobre programação em linguagem C a serem resolvidas em laboratório. Essa prova terá que ser resolvida iniciando às 7:30 e terminando no máximo às 10:30 h.

Conceitos do projeto

Aluno Conceito
Fernando C
Gabriel D*
Levi D*
Lindalvo C
Marcos A
Marine D
Mario Allan A
Mário André A
Mário Sérgio D
Maykon B
Nathany D
Paulo Igor D*
Ricardo D
Roberto D*
Thiago Martins D*
Thiago Ramos D*
Vinicius Kachniacz D*
Vinicius Rodrigues D

Obs: D* = não apresentou o projeto (desistente)

20/12: Recuperação

A prova de recuperação terá ao menos quatro questões sobre programação em linguagem C a serem resolvidas em laboratório. Essa prova terá que ser resolvida iniciando às 7:30 e terminando no máximo às 10:30 h. Essa prova será a mesma para quem precisar recuperar Lógica de Programação.