0% acharam este documento útil (0 voto)
6 visualizações99 páginas

Introdução ao QBasic e Programação

As notas de aula de Introdução à Ciência da Computação abordam conceitos fundamentais da programação usando a linguagem QBasic, incluindo algoritmos, variáveis, tipos de dados e controle de fluxo. O curso visa capacitar os alunos a resolver problemas computacionais através de uma linguagem imperativa, com ênfase em estruturas de dados e funções. O QBasic é escolhido por sua simplicidade e acessibilidade, facilitando a compreensão dos princípios da programação.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
6 visualizações99 páginas

Introdução ao QBasic e Programação

As notas de aula de Introdução à Ciência da Computação abordam conceitos fundamentais da programação usando a linguagem QBasic, incluindo algoritmos, variáveis, tipos de dados e controle de fluxo. O curso visa capacitar os alunos a resolver problemas computacionais através de uma linguagem imperativa, com ênfase em estruturas de dados e funções. O QBasic é escolhido por sua simplicidade e acessibilidade, facilitando a compreensão dos princípios da programação.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Notas de aula de Introdução à Ciência da

Computação

Daniel Oliveira Dantas

22 de abril de 2024
Sumário

1 Introdução 1
1.1 Conteúdo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Passos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Instalando o QBasic . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Um primeiro programa em QBasic . . . . . . . . . . . . . . . . . . 4
1.5 Uso do help e especificação da sintaxe . . . . . . . . . . . . . . . . 11
1.6 Comentários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.7 Palavras-chave ou keywords . . . . . . . . . . . . . . . . . . . . . . 13
1.8 Literais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.9 Tipos de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.10 Identificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.11 Variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.12 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.13 Expressões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.13.1 Expressões numéricas . . . . . . . . . . . . . . . . . . . . . . 17
1.13.2 Expressões de strings . . . . . . . . . . . . . . . . . . . . . . 19
1.14 Funções elementares . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.14.1 Funções numéricas . . . . . . . . . . . . . . . . . . . . . . . 20
1.14.2 Funções de strings . . . . . . . . . . . . . . . . . . . . . . . . 23
1.15 Entrada de dados no console . . . . . . . . . . . . . . . . . . . . . . 24
1.16 Saı́da de dados no console . . . . . . . . . . . . . . . . . . . . . . . 25
1.17 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2 Controle de fluxo 29
2.1 Saltos condicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1.1 Instrução IF . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1.2 Instrução SELECT . . . . . . . . . . . . . . . . . . . . . . . 31
2.2 Laços . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.1 Instrução FOR . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.2 Instrução WHILE...WEND . . . . . . . . . . . . . . . . . . 34
2.2.3 Instrução DO...LOOP . . . . . . . . . . . . . . . . . . . . . 36
2.3 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

iii
3 Tipos de dados compostos 41
3.1 Estruturas compostas homogêneas . . . . . . . . . . . . . . . . . . 41
3.2 Estruturas compostas heterogêneas . . . . . . . . . . . . . . . . . . 42
3.3 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

4 Funções e procedimentos 45
4.1 Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.2 Procedimentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.3 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4.4 Arrays como parâmetros . . . . . . . . . . . . . . . . . . . . . . . . 49
4.5 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

5 Som e gráficos 51
5.1 Som . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.2 Gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.2.1 Tiles and sprites . . . . . . . . . . . . . . . . . . . . . . . . . 60
5.3 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

6 Jogos baseados em texto 73


6.1 Um RPG simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
6.2 Animação e ASCII art . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.3 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

7 Interação com o teclado e game loop 83


7.1 Interação com o teclado . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.2 Game loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7.3 Exercı́cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

A Tabela ASCII 91

iv
Capı́tulo 1

Introdução

O objetivo deste curso é preparar o aluno para resolver problemas computacio-


nais através de uma linguagem imperativa. Uma linguagem imperativa é usada
para enviar instruções ao computador, ou seja, o que deve ser feito e como.
Linguagens imperativas podem ser divididas entre estruturadas e orientadas a
objeto. Nas linguagens estruturadas, o código é organizado em instruções, sal-
tos condicionais e laços. Uma especialização das linguagens estruturadas são as
linguagens procedurais, que permitem ainda a organização do código em funções
ou procedimentos. Nas linguagens orientadas a objeto, o código é organizado
em classes, que possuem atributos para armazenar os dados e métodos para
processá-los.
Linguagens declarativas se contrapõem às linguagens imperativas pois nelas
o programador diz o que deve ser feito sem especificar como, ou seja, o foco é
no resultado.
Escolhemos o QBasic por ser uma linguagem didática e amigável. Permite
fácil acesso à tela, simplificando a geração de gráficos e saı́da de texto formatada.
É uma linguagem de alto nı́vel, ou seja, é expressiva, legı́vel e simples de usar.
Linguagens de baixo nı́vel por sua vez, por estarem mais próximas da linguagem
de máquina, são menos expressivas e mais difı́ceis de usar.
O QBasic permite uma introdução suave aos conceitos fundamentais da pro-
gramação, como entrada e saı́da, variáveis, expressões aritméticas e lógicas,
operações condicionais, controle de fluxo, extruturas de dados, funções, recursi-
vidade e algoritmos básicos. Estes conceitos serão apresentados neste curso.
O QBasic é uma linguagem case-insensitive, com tipagem estática e fraca.
Case-insensitive porque letras maiúsculas e minúsculas não se distinguem. Se
diz que o QBasic tem tipagem estática pois o tipo de uma variável, uma vez
definido, não muda mais. Se diz que QBasic tem tipagem fraca pois é possı́vel
realizar operações entre variáveis de tipos diferentes, como somar inteiros e reais.

1
1.1 Conteúdo
O objetivo deste curso é tornar o aluno apto a resolver problemas computáveis
com o uso de uma linguagem imperativa.
Os objetivos especı́ficos são

• Ensinar noções fundamentais sobre algoritmos e resolução de problemas;

• Explorar as principais conceitos utilizados no paradigma imperativo;

• Apresentar uma linguagem imperativa.

Os tópicos a serem vistos são

• Noções fundamentais sobre algoritmos e sobre a execução de programas.

• Solução de problemas. Abordagem top-down.

• Identificadores, variáveis, constantes e atribuição.

• Tipos de dados.

• Expressões. Operadores: aritméticos, lógicos e relacionais.

• Instruções condicionais.

• Instruções de repetição.

• Variáveis compostas homogêneas: vetores e matrizes ou listas e tuplas.

• Variáveis compostas heterogêneas: registros ou dicionários.

• Procedimentos, funções e passagem de parâmetros.

• Recursividade.

• Noções sobre o uso de arquivos em programação.

• Algoritmos básicos de ordenação.

• Uma linguagem imperativa.

Ao finalizar o curso, o aluno deve ser capaz de abordar problemas compu-


tacionais simples utilizando uma linguagem imperativa. Deve estar preparado
para aprender outros paradigmas de programação e estruturas de dados.

2
1.2 Passos futuros
Uma vez que o leitor tenha completado o curso e esteja familiarizado com os
conceitos apresentados, pode abordar problemas mais avançados. Nesse caso,
outras linguagens podem ser necessárias a depender do problema a ser resolvido.
Os conceitos apresentados neste curso podem ser encontrados em qualquer lin-
guagem imperativa.
• Programação de páginas dinâmicas para a web: PHP, Python, Javascript.
• Interfaces gráficas: Visual Basic (.NET), Python com Tkinter.
• Computação gráfica: C++ com OpenGL.
• Jogos complexos: C++ com Unreal.
• Computação cientı́fica: Python, Fortran.
• Computação paralela: C++ com CUDA, OpenCL ou GLSL.
• Análises estatı́sticas: R.
A depender da aplicação, uma linguagem declarativa pode ser necessária.
• Bancos de dados: SQL.
• Programação funcional: Haskell.
• Programação lógica: Lisp, Prolog.
• Demonstração de teoremas: Coq, Isabelle, Lean.

1.3 Instalando o QBasic


O primeiro passo para começar a programar em QBasic é instalar o interpreta-
dor ou compilador da linguagem. Existem diversas versões. Recomendamos o
QuickBasic 4.51 , que possui compilador, e pode gerar executáveis.
O QuickBasic 4.5 requer a instalação do emulador DosBox2 . Uma vez insta-
lado o DosBox e montada a pasta que contém sua árvore de diretórios, acesse a
pasta QB45 e execute o [Link]. A Figura 1.1 mostra a tela inicial do Quick-
Basic 4.5.
Alternativamente, pode ser usado o QB643 , que não exige o uso do DosBox.
O QB64 é compatı́vel com versões x64 do Windows e Linux. A Figura 1.2
mostra a tela inicial do QB64. As versões citadas possuem pequenas diferenças
entre si, porém, ao longo do texto, QBasic se refere a ambas indistintamente.
Caso necessário, a versão especı́fica do QBasic será explicitada.
Uma terceira possibilidade, porém recomendada apenas para testes rápidos
em computadores públicos, é o QBJS4 . O QBJS é um interpretador disponı́vel
1 [Link]
2 [Link]
3 [Link]
4 [Link]

3
online, porém, não possui todas as funcionalidades e keywords implementados,
apenas os mais simples, e portanto sua funcionalidade é limitada. A Figura 1.3
mostra uma tela de exemplo do QBJS.
Existe ainda a possibilidade de rodar o QuickBasic 4.5 online5 . Esta versão
possui compatibilidade total com o QuickBasic 4.5. O problema é a impossibi-
lidade de salvar os programas inseridos.

1.4 Um primeiro programa em QBasic


Este programa curto imprime a mensagem “Hello, World!” no console, ou seja,
na tela de saı́da. Pressione a tecla [F5] e o programa será executado. A mensa-
gem será impressa e, na última linha, aparecerá a mensagem “Press any key to
continue”, indicando que o programa foi finalizado.
PRINT " Hello world ! "

Todo código será mostrado em caixas com fundo azul. A saı́da resultante
será mostrada em caixas com fundo preto. Abaixo está a saı́da do programa.
Hello world !

Press any key to continue

Pressione qualquer tecla para retornar ao ambiente de programação. Você


pode executar o programa novamente pressionando mais uma vez a tecla [F5]
e a mensagem será impressa novamente na linha seguinte. Para evitar isso, é
preciso limpar a tela antes de imprimir a mensagem. Isso pode ser feito com a
instrução CLS, que significa clear screen.
CLS
PRINT " Hello world ! "

A Figura 1.4 mostra o código do programa no ambiente de programação


do QuickBasic. A Figura 1.5 mostra o console com a saı́da resultante de sua
execução.
5 [Link]

4
É uma boa prática salvar frequentemente o código sendo desenvolvido. Isso
evita a perda do trabalho em caso de encerramento acidental do ambiente de
programação ou desligamento do computador. A Figura 1.6 mostra a janela de
diálogo usada para salvar o código fonte. Use sempre o formato de texto, para
que o código fonte possa ser lido por outros programas.
Podemos também imprimir valores numéricos, inteiros ou de ponto flutuante
(não inteiros), positivos ou negativos. Caso o número seja de ponto flutuante
com mais do que sete dı́gitos, o interpretador automaticamente adicionará o
sı́mbolo # para explicitar que o número é de dupla precisão.
PRINT 256
PRINT 3.14
PRINT -10
PRINT .00000001#
PRINT 1234.56789#

Abaixo está a saı́da gerada. Observe que os números positivos são precedidos
por um espaço em branco e os negativos por um sinal de menos. A partir daqui
omitiremos a mensagem “Press any key to continue” da saı́da do programa.
256
3.14
-10
.00000001
1234.56789

Para executar o programa passo a passo, pressione a tecla [F8]. No QBasic,


a tecla [F4] alterna entre o ambiente de programação e o console de saı́da. A
tecla [F5] continua a execução e [Shift+F5] reinicia o programa.
A instrução PRINT também aceita múltiplos parâmetros simultaneamente.
Quando separados por vı́rgula, cada item será impresso em um bloco com ta-
manho igual a 14 caracteres. Quando separados por ponto e vı́rgula, serão
impressos imediatamente um após o outro. Cada número é sucedido por um
caractere em branco. Uma instrução PRINT sem parâmetros pula uma linha.
PRINT 1 , 2 , 3 , 4
PRINT
PRINT 5; 6; 7; 8; 9

Abaixo está a saı́da gerada.


1 2 3 4

5 6 7 8 9

5
O QBasic pode ser usado como calculadora. Um programa em QBasic pode
mandar imprimir o resultado de expressões aritméticas e lógicas. Alternativa-
mente, pressione a tecla [F6] para alternar para a janela Immediate. A janela
Immediate permite a execução de uma linha de código de cada vez para fazer
cálculos e outros testes rápidos.

Tabela 1.1: Operações aritméticas do QBasic

Operação Operador
Soma +
Subtração, menos unário -
Produto *
Divisão /
Divisão inteira \
Potenciação ^
Módulo MOD
Sinais de pontuação ( )

A Tabela 1.1 mostra as operações aritméticas suportadas pela linguagem.


Abaixo estão alguns exemplos de cálculos feitos com o QBasic.
PRINT 10 + 10 , 10 - 10
PRINT -10 - 10
PRINT 10 * 10
PRINT 10 / 4 , 10 \ 4
PRINT 2 ^ 10
PRINT 15 MOD 2 , 15 MOD 3 , 15 MOD 4
PRINT ((2 + 3) * 5) , 2 + 3 * 5

Abaixo está a saı́da gerada.


20 0
-20
100
2.5 2
1024
1 0 3
25 17

Caso seja necessário reutilizar algum valor repetidas vezes, é recomendável


armazená-lo em uma variável. No exemplo abaixo, são declaradas as variáveis
pi e dez.
pi = 3.1415
dez = 10
PRINT dez ^ 3

6
PRINT dez * pi
PRINT pi / 2

7
Figura 1.1: Tela inicial do QuickBasic 4.5.

Figura 1.2: Tela inicial do QB64.

8
Figura 1.3: Tela do QBJS.

Figura 1.4: Programa de exemplo.

9
Figura 1.5: Tela de saı́da do programa.

Figura 1.6: Janela de diálogo de salvamento do código. Use sempre formato


texto.

10
Abaixo está a saı́da gerada.
1000
31.415
1.57075

Tabela 1.2: Algumas funções numéricas do QBasic

Operação Função
Seno SIN
Cosseno COS
Tangente TAN
Raiz quadrada SQR
Logaritmo Neperiano LOG
Sinal SGN

O QBasic possui diversas funções numéricas. A Tabela 1.2 mostra algumas


delas. Essas funções podem ser usadas em cálculos diversos. Para usar uma
função, colocamos os parâmetros entre parênteses após seu nome
pi = 3.1415
PRINT SIN ( pi /4)
PRINT TAN ( pi /4)
PRINT LOG (1) ; LOG (10)
PRINT SGN ( -5) ; SGN (0) ; SGN (5)

Abaixo está a saı́da gerada.


.7070904
.9999537
0 2.302585
-1 0 1

1.5 Uso do help e especificação da sintaxe


O help do QBasic pode ser acessado pressionando [Shift+F1]. O help dá detalhes
sobre todas as instruções do QBasic, o que fazem, como usá-los, sua sintaxe e
alguns exemplos de uso. Pressionando [Shift+F1], depois acessando <Contents>
e em seguida <Syntax Notation Conventions>, são exibidas as convenções
usadas na especificação da sintaxe das instruções do QBasic. São essencialmente
as seguintes:

11
• KEYWORDS: em letras maiúsculas são mostradas as palavras-chave da lin-
guagem. Devem ser digitados exatamente como aparecem no help.

• placeholders: em letras minúsculas são mostrados itens que devem ser


substituı́dos pelos parâmetros necessários para a chamada da instrução,
como valores numéricos e strings (sequências de caracteres).

• [optional item]: entre colchetes são mostrados itens opcionais.

• {choice1 | choice2}: entre chaves e separados por uma barra vertical


são mostradas as alternativas a serem usadas na instrução.

Quando precisar acessar o help sobre alguma instrução especı́fica, posicione


o cursor sobre ela e pressione a tecla [F1]. Vejamos por exemplo a ajuda sobre a
instrução PRINT. A partir da janela que contém o código fonte, posicionando o
cursor sobre a instrução PRINT e pressionando [F1], a ajuda sobre esta instrução
será exibida na tela. Pressione [F6] para acessar a janela do help, e [Esc] para
fechá-la. A Figura 1.7 mostra a tela de ajuda da instrução PRINT.

Figura 1.7: Ajuda sobre a instrução PRINT.

A ajuda da instrução PRINT mostra a seguinte sintaxe:


PRINT [ expression_list ][{ ,|;}]

A palavra PRINT é o keyword. A palavra expression list representa a


lista de expressões cujos resultados serão impressos. Como está em colchetes, é
opcional e, quando omitida, a instrução PRINT imprime uma linha em branco.
A instrução PRINT pode terminar por uma vı́rgula ou por um ponto e vı́rgula.

12
Ambos estão entre chaves, o que significa que é possı́vel escolher um ou o ou-
tro. Além disso, estão entre colchetes, o que significa que podem ser omitidos.
Quando a linha termina por vı́rgula, a próxima impressão será no próximo bloco
de 14 caracteres; quando termina em ponto e vı́rgula, será logo em seguida, e
quando termina sem nenhum dos dois, será na próxima linha.

1.6 Comentários
Comentários são textos ignorados pelo compilador. Dentro de um comentário é
possı́vel escrever qualquer coisa, sem risco de erros de compilação. Comentários
são importantes para documentar o código, facilitando o entendimento por ou-
tros programadores que precisem usá-lo e até mesmo para o próprio criador
do código lembrar detalhes importantes sobre seu funcionamento. Em QBasic
existem dois tipos de comentário:

• Comentários iniciados com REM: não devem suceder nenhuma instrução.

• Comentários iniciados com apóstrofe: podem suceder alguma instrução.

Exemplo de programa com comentários.

REM this is a QBasic program


’ Text inside a comment is ignored
PRINT " Hi " ’ This comment can succeed a command .

1.7 Palavras-chave ou keywords


Palavras-chave ou keywords são instruções ou funções predefinidas pelo QBasic.
Portanto, essas palavras não podem ser usadas para nomear variáveis ou funções
criadas pelo usuário. A lista de palavras-chave do QBasic pode ser acessada
pressionando [Shift+F1] e depois acessando <Index>. Pressionando [Shift+F1],
depois acessando <Contents> e em seguida <Functional Keyword List>, são
exibidas as palavras chave agrupadas por funcionalidade. Abaixo está uma lista
não exaustiva de palavras-chave do QBasic.

13
Estruturas de decis~
ao: IF...ELSE Operadores ABS
SELECT...CASE funcionais: SIN
COS
Construç~
ao de laços: FOR...NEXT TAN
DO...LOOP ATN
WHILE...WEND LOG
EXP
Entrada e saı́da LOCATE SGN
no console: PRINT SQR
PRINT USING INT
INPUT$ RND
INKEY$
Operadores NOT
Entrada e saı́da OPEN lógicos: AND
em arquivo: WRITE # OR
INPUT # XOR
EQV
Entrada e saı́da SCREEN IMP
gráfica: DRAW
COLOR Funç~
oes de ASC
PALETTE string: CHR$
LINE LEN
CIRCLE LEFT$
PSET MID$
RIGHT$
Saı́da de áudio: BEEP VAL
PLAY STR$

1.8 Literais

Literais são valores que ocorrem no programa. Podem ser de diversos tipos.

Números inteiros: 0
-1
333
Números reais: 2.0
3.1415
-1000.0
Strings: "Hello world"
"bom dia"
"Idade = 22 anos"

14
1.9 Tipos de dados
O QBasic suporta cinco tipos de dados primitivos. São usados para declarar
explicitamente o tipo das variáveis. Suporta ainda um tipo user-defined que é
uma composição de tipos primitivos usados como campos de um registro. Outro
tipo de dado composto é o vetor ou matriz, que armazena valores de um mesmo
tipo indexados, ou seja, acessı́veis através de um ı́ndice inteiro.

Tabela 1.3: Tipos de dados do QBasic.

Descrição Tipo Bytes Sufixo Mı́nimo Máximo


String STRING - $ 0 char. 32767 char.
Inteiro INTEGER 2 % −215 215 − 1
Inteiro longo LONG 4 & −231 231 − 1
Real até 7 dı́gitos SINGLE 4 ! 1.4 × 10−45 3.4 × 1038
Real até 14 dı́gitos DOUBLE 8 # 4.9 × 10−324 1.7 × 10308

1.10 Identificadores
Identificadores são os nomes de variáveis, funções, constantes e outros objetos
criados pelo usuário. É uma sequência de caracteres tal que

• Possui de um a 40 caracteres
• O primeiro caractere pode ser letra
• Os demais caracteres podem ser letras ou dı́gitos.
• Não pode ser igual a nenhuma palavra reservada.
• Pode terminar em um sufixo de tipo como da Tabela 1.3.
• Exemplos:

Corretos: ABC Incorretos: 123


contador i+1
x# a!b
x2 rem
nome$ val

1.11 Variáveis
Variáveis são posições de memória com um nome, usadas para armazenar va-
lores. Os valores armazenados podem ser modificados a qualquer momento.
O nome de uma variável deve ser um identificador válido, como descrito na
Seção 1.10. Sua declaração e inicialização devem aparecer no código antes de
seu primeiro uso.

15
• A declaração de uma variável é onde definimos seu tipo e seu identificador,
isto é, seu nome.

• A inicialização de uma variável é onde atribuı́mos a ela algum valor pela


primeira vez.

Variáveis numéricas não inicializadas possuem valor igual a zero e strings não
inicializadas são vazias. A declaração de uma variável possui a sintaxe abaixo.
DIM variable [ AS type ]

DIM nome AS STRING


DIM num AS SHORT
DIM grande AS LONG
DIM valor AS SINGLE
DIM real AS DOUBLE

É possı́vel declarar e inicializar as variáveis simultaneamente. As declarações


abaixo também são mais simples e diretas. O sufixo de tipo pode ser usado para
definir o tipo da variável de maneira mais econômica do que na sintaxe anterior.
Abaixo é mostrada a sintaxe e código com exemplos de declarações de variáveis
com inicialização simultânea.
variable_name = expression

nome$ = " Knuth "


num % = 1000
grande & = 123456789
valor ! = .25
real # = 1/3

Se omitido o sufixo de tipo, o QBasic definirá o tipo da variável automati-


camente a partir do valor atribuı́do a ela.
nome = " Knuth "
num = 1000
grande = 123456789
valor = .25
real = 1/3

16
1.12 Constantes
Como variáveis, constantes são posições de memória que armazenam algum
valor. Porém ao contrário de variáveis, o valor não pode ser modificado. A
declaração de uma constante possui a sintaxe abaixo.
CONST constant_name = expression

Abaixo estão alguns exemplos de declarações de constantes. Como nas de-


clarações de variáveis, o sufixo de tipo pode ser omitido.
CONST c = 299792458
CONST pi = 3.141 592653 58979#
CONST G = 6.67428 E -11

1.13 Expressões
Expressões podem ser numéricas ou strings. Expressões numéricas por sua vez
podem ser aritméticas ou lógicas.

1.13.1 Expressões numéricas


Expressões numéricas retornam valores numéricos como resultado. Expressões
numéricas primitivas possuem apenas operandos enquanto compostas possuem
operandos concatenados com operadores. Abaixo está a sintaxe de expressões
numéricas primitivas
literal
numeric_function
variable
constant

O código abaixo mostra a declaração de uma variável e de uma constante.


Em seguida mostra exemplos de instruções PRINT imprimindo o resultado de
expressões numéricas primitivas, ou seja, expressões com apenas operandos.
n = 123 ’ Declaracao de variavel
CONST pi = 3.14 ’ Declaracao de constante
’ Abaixo as expressoes sucedem o PRINT
PRINT 100 ’ Expressao com literal
PRINT SIN ( pi ) ’ Funcao que retorna valor
PRINT n ’ Expressao com variavel
PRINT pi ’ Expressao com constante

17
Expressões numéricas compostas são uma concatenação de operadores e ope-
randos. Os operandos podem ser expressões primitivas ou outras expressões
compostas. Os operadores podem ser aritméticos, de comparação ou lógicos.
Expressões numéricas retornam algum valor numérico. Expressões aritméticas
são o resultado de operações aritméticas. Expressões lógicas são o resultado de
comparações ou de operações Booleanas. Seu resultado também é numérico mas
é interpretado como verdadeiro ou falso. Em QBasic não há um tipo Booleano
nativo, então o 0 é interpretado como falso e -1 como verdadeiro.
Operadores podem ser unários ou binários. Operadores unários operam so-
bre um operando, enquanto os binários operam sobre dois. Abaixo está a sintaxe
de expressões numéricas compostas.
expression binary_operator expression
unary_operator expression

O código abaixo mostra a declaração de uma variável e de uma constante.


Em seguida mostra exemplos de instruções PRINT imprimindo o resultado de
expressões numéricas compostas.
CONST pi = 3.14 ’ Declaracao de constante
n = 123 ’ Declaracao de variavel
’ Abaixo as expressoes sucedem o PRINT
PRINT -100 ’ Expressao aritmetica , op . unario
PRINT 100 + 11 ’ Expressao aritmetica , op . binario
PRINT 10 > 0 ’ Expressao logica de comparacao
PRINT 1 AND 1 ’ Expressao logica Booleana

Abaixo estão os operadores aritméticos ordenados por precedência.


Preced^encia:
maior ^ (Exponenciaç~ ao)
- (menos unário)
* / (multiplicaç~ ao e divis~ao)
\ (divis~ ao inteira)
MOD (módulo)
menor + - (soma e subtraç~ ao)

• Operadores de maior precedência são avaliados antes dos de menor pre-


cedência.

• Operadores com mesmo nı́vel de precedência são avaliados da esquerda


para a direita.

• É possı́vel usar parênteses para modificar a ordem das operações.

Nos exemplos abaixo, que valor é atribuı́do à variável à esquerda do =?

18
a = 2 * 3 + 1;
b = 1 + 2 * 3;
c = 10 / 2 * 5;
d = 10 MOD 3;
e = 2 * 10 MOD 4;
f = 3 * (2 + 1) ;

Expressões com operadores lógicos ou de comparação também retornam va-


lores numéricos. O 0 é interpretado como falso e -1 como verdadeiro. Não há
em QBasic um tipo de dados Booleano. A tabela abaixo mostra os operadores
de comparação. Todos possuem a mesma precedência
> >= < <= (desigualdade)
= <> (igualdade e diferença)
A tabela abaixo mostra a ordem de precedência dos operadores Booleanos. Os
operadores Booleanos também são operadores bit a bit, ou seja, operam sobre
bits individuais de seus operandos.
Preced^encia:
maior NOT (complemento de um)
AND (and binário)
OR (or binário)
XOR (xor binário)
EQV (equival^encia binária)
menor IMP (implicacao binária)
Nos exemplos abaixo, que valor é atribuı́do à variável à esquerda do =?
a = 1 < 2;
b = -1 OR 0;
c = -1 AND 0;
d = (1 < 2) OR (4 < 2) ;
e = (1 < 2) AND (4 < 2) ;
f = 1 < 1;
g = NOT (3 < 2) ;
h = 3 = 4;
i = 3 <> 4;

1.13.2 Expressões de strings


Expressões primitivas de strings podem ser literais, variáveis ou constantes do
tipo string, ou funções que retornam uma string. É possı́vel concatenar strings
com o operador +. Também é possı́vel comparar strings com os operadores de
comparação.

19
O código abaixo mostra a declaração de uma variável e de uma constante.
Em seguida mostra exemplos de instruções PRINT imprimindo o resultado de
expressões com strings.
CONST a = " aaa " ’ Declaracao de constante
b = " bbb " ’ Declaracao de variavel
’ Abaixo as expressoes sucedem o PRINT
PRINT " Hi " ’ Expressao com literal
PRINT CHR$ (65) ’ Funcao que retorna valor
PRINT b ’ Expressao com variavel
PRINT a ’ Expressao com constante
PRINT a + b ’ Expressao com concatenacao
PRINT a <= b ’ Expressao comparacao

1.14 Funções elementares


Nesta seção descrevemos algumas funções elementares embutidas na linguagem.
Estão divididas em funções numéricas e funções de strings.

1.14.1 Funções numéricas


As funções numéricas retornam números como resultado. Podem ser usadas
para compor expressões numéricas. A Tabela 1.4 lista as funções numéricas
descritas nesta seção.
As funções trigonométricas SIN, COS e TAN possuem a sintaxe abaixo. O
parâmetro numeric_expression é o ângulo em radianos. O ângulo em radianos
é igual ao ângulo em graus multiplicado por pi sobre 180.
SIN ( nu me ri c_ exp re ss io n )
COS ( nu me ri c_ exp re ss io n )
TAN ( nu me ri c_ exp re ss io n )

A função trigonométrica ATN possui a sintaxe abaixo. A função retorna o


ângulo correspondente ao valor do parâmetro numeric_expression.
ATN ( nu me ri c_ exp re ss io n )

A função SQR possui a sintaxe abaixo. A função retorna a raiz quadrada do


parâmetro numeric_expression. O parâmetro deve ser maior ou igual a zero.
SQR ( nu me ri c_ exp re ss io n )

20
Tabela 1.4: Funções numéricas do QBasic

Operação Função
Seno SIN
Cosseno COS
Tangente TAN
Arco tangente ATN
Raiz quadrada SQR
Logaritmo Neperiano LOG
Exponencial Neperiana EXP
Sinal SGN
Valor absoluto ABS
Truncar FIX
Piso (floor) INT
Arredondar CINT
Arredondar para LONG CLNG
Converte para SINGLE CSNG
Converte para DOUBLE CDBL
String para número VAL
Código ASCII do caractere ASC
Segundos desde meia-noite TIMER
Gera número aleatório RND
Altera random seed RANDOMIZE

As funções LOG e EXP possuem a sintaxe abaixo. A função LOG retorna o lo-
garitmo natural, i.e., logaritmo Neperiano, do parâmetro numeric_expression.
O parâmetro deve ser maior que zero. A função EXP retorna o valor da função
exponencial natural, i.e., o número de Euler elevado ao valor do parâmetro
numeric_expression.
LOG ( nu me ri c_ exp re ss io n )
EXP ( nu me ri c_ exp re ss io n )

As funções SGN e ABS possuem a sintaxe abaixo. A função SGN retorna -1 se o


valor do parâmetro numeric_expression for negativo; retorna 0 se o parâmetro
for 0; e retorna +1 se o parâmetro for maior que zero. A função ABS retorna o
valor absoluto do parâmetro numeric_expression, ou seja, o valor sem o sinal,
também conhecido como módulo.
SGN ( nu me ri c_ exp re ss io n )
ABS ( nu me ri c_ exp re ss io n )

As funções FIX, INT, CINT, CLNG, CSNG e CDBL possuem a sintaxe abaixo.
A função FIX retorna a parte inteira do parâmetro numeric_expression. A

21
função INT retorna o piso (floor) de numeric_expression, ou seja, o maior
inteiro menor que o parâmetro. As funções CINT e CLNG arredondam o valor de
numeric_expression retornando respectivamente um INTEGER e um LONG. As
funções CSNG e CLNG convertem o valor de numeric_expression para os tipos
SINGLE e DOUBLE respectivamente.
FIX ( nu me ri c_ exp re ss io n )
INT ( nu me ri c_ exp re ss io n )
CINT ( num er ic _e xp re ss io n )
CLNG ( num er ic _e xp re ss io n )
CSNG ( num er ic _e xp re ss io n )
CDBL ( num er ic _e xp re ss io n )

As funções VAL e ASC são ditas numéricas pois retornam valores numéricos.
Também são funções de processamento de strings pois recebem uma string como
parâmetro. A função VAL retorna o valor numérico representado no parãmetro
string_expression. A função ASC retorna o valor ASCII do primeiro caractere
de string_expression. O Apêndice A lista os valores ASCII dos caracteres.
VAL ( s tring_ expres sion )
ASC ( s tring_ expres sion )

A função TIMER retorna o número de segundos passados desde meia-noite.


A função RND, a cada vez que é chamada, retorna um número pseudoaleatório
entre 0 e 1. A cada vez que o programa reinicia, a função vai retornar exa-
tamente a mesma sequência. Para mudar a sequência retornada, é necessário
chamar RANDOMIZE no inı́cio do programa com uma random seed numérica como
parâmetro, que define uma nova sequência. Basta chamar RANDOMIZE uma única
vez ao iniciar a execução do programa.
TIMER
RND
RANDOMIZE [ nu me ri c_ ex pr es si on ]

Uma maneira de gerar uma sequência diferente a cada execução do programa


é chamando RANDOMIZE e passando TIMER como parâmetro. O código abaixo
mostra como gerar um valor aleatório de 1 a 6.
RANDOMIZE TIMER
v = RND
PRINT INT ( v * 6) + 1

22
1.14.2 Funções de strings
As funções de strings retornam uma string como resultado. Podem ser usadas
para compor expressões de strings. A Tabela 1.5 lista as funções de strings
descritas nesta seção.

Tabela 1.5: Funções de strings do QBasic

Operação Função
Número para string STR$
Número para hexadecimal HEX$
Número para octal OCT$
Caractere do código ASCII CHR$
Caracteres à esquerda LEFT$
Caracteres à direita RIGHT$
Caracteres do meio MID$
String com n espaços SPACE$
String com n caracteres STRING$

As funções STR$, HEX$, OCT$e CHR$ são ditas de strings pois retornam strings
como resultado. A função STR$ converte o valor numérico de numeric_expression
para sua representação em forma de string. A função HEX$ converte o valor
numérico para uma string com sua representação em hexadecimal e OCT$ para
sua representação em octal. Já a função CHR$ retorna o caractere ASCII cor-
respondente ao valor do parâmetro numeric_expression. O Apêndice A lista
os valores ASCII dos caracteres.
STR$ ( nu me ri c_ ex pr es si on )
HEX$ ( nu me ri c_ ex pr es si on )
OCT$ ( nu me ri c_ ex pr es si on )
CHR$ ( nu me ri c_ ex pr es si on )

As funções LEFT$, RIGHT$ e MID$ possuem a sintaxe abaixo. A função LEFT$


retorna os n caracteres mais à esquerda de string_expression. A função
RIGHT$ retorna os n caracteres mais à direita de string_expression. A função
MID$ retorna os n caracteres a partir da posição m da string. O n e o m são
expressões numéricas.
LEFT$ ( string_expression , n )
RIGHT$ ( string_expression , n )
MID$ ( string_expression , m , n )

As funções SPACE$ e STRING$ possuem a sintaxe abaixo. A função SPACE$


retorna uma string com n espaços. A função STRING$ retorna uma string com
n repetições do caractere definido por expression. Se expression for do tipo

23
STRING, será usado seu primeiro caractere; se for número, será usado o caractere
com o código ASCII correspondente. O n é expressão numérica. No Apêncide A
há uma tabela ASCII.
SPACE$ ( n )
STRING$ (n , expression )

1.15 Entrada de dados no console


Um programa que começa com os mesmos dados sempre retornará o mesmo
resultado. Uma maneira de aumentar a flexibilidade do programa é permitir a
entrada de dados do usuário. Com a instrução INPUT é possı́vel inserir dados
numéricos ou strings.
A sintaxe da instrução INPUT é a seguinte:
INPUT [;][ " promptstring " {;| ,}] variablelist

O primeiro ponto e vı́rgula é opcional e faz com que o cursor permaneça na


mesma linha após o usuário pressionar [Enter]. A mensagem promptstring é
opcional e é impressa antes do cursor. O segundo ponto e vı́rgula faz com que
apareça um ponto de interrogação antes do cursor. A alternativa é a vı́rgula, que
omite o ponto de interrogação. A variablelist é uma lista de variáveis sepa-
radas por vı́rgula. Caso variablelist possua apenas uma variável, o usuário
deve inserı́-la e depois pressionar [Enter]. Caso a lista possua mais de uma
variável, o usuário deve digitar vı́rgula entre elas.
Abaixo está um exemplo de entrada de um dado numérico. Observe que a
variável possui tipo LONG.
INPUT " Digite sua idade : " , idade &
PRINT " Voce digitou " ; idade &

Abaixo está um exemplo de entrada de uma string. Observe que a variável


possui tipo STRING.
INPUT " Digite seu nome : " , nome$
PRINT " Voce digitou " ; nome$

Abaixo está um exemplo de entrada de três valores reais. Observe que as


variáveis possuem tipo SINGLE
INPUT " Digite os lados da caixa : " , a ! , b ! , c !
PRINT " Seu volume eh " ; a ! * b ! * c !

24
1.16 Saı́da de dados no console
Nesta seção descrevemos algumas funções úteis para saı́da de dados formatada
no console. A Tabela 1.6 lista as funções descritas nesta seção.

Tabela 1.6: Funções para saı́da de dados formatada no console

Operação Função
Tabulação TAB
Espaçamento SPC
Linha atual do cursor CSRLIN
Coluna atual do cursor POS
Posiciona o cursor LOCATE
Impressão formatada PRINT USING

Abaixo está a sintaxe das funções de saı́da de dados formatada no console.


TAB ( nu me ri c_ exp re ss io n )
SPC ( nu me ri c_ exp re ss io n )
CSRLIN
POS
LOCATE [ row ][ , column ]
PRINT USING formatstring ; expression_list [{ ,|;}]

A função TAB avança o cursor até a coluna especificada pelo parâmetro


numeric_expression. A função SPC imprime o número de espaços especifica-
dos por numeric_expression. Ambas são usadas como parâmetros de PRINT.
CSRLIN retorna a linha atual em que está o cursor e POS retorna a coluna. LOCATE
posiciona o cursor na linha e coluna especificadas por row e column. Se apenas
um dos parâmetros for especificado, apenas a coordenada correspondente a ele
muda.
A função PRINT USING pode ser usada para formatar a saı́da de números e
texto conforme a especificação de format_string. Os caracteres tipicamente
usados na especificação são "#", "." e " " para especificar respectivamente
posição de dı́gito, ponto decimal e espaçamento. Texto não correspondente a
caracteres especiais é interpretado literalmente. Abaixo estão alguns exemplos.
nota1 = 9.55
nota2 = 10.0
PRINT USING " ##.# " ; nota1 ;
PRINT USING " ##.# " ; nota1 ; nota2
PRINT USING " ##.### " ; nota1 ; nota2
PRINT USING " ##.# ##.# " ; nota1 , nota2
PRINT USING " Nota 1: ##.# Nota2 : ##.# " ; nota1 , nota2

25
1.17 Exercı́cios
1. Crie um programa e dentro dele declare as seguintes variáveis

(a) um inteiro chamado n.


(b) um inteiro longo chamado l.
(c) um real de precisão simples chamado f.
(d) um real de precisão dupla chamado d.
(e) uma string chamada s.

2. Crie um programa e dentro dele declare e inicialize na mesma instrução

(a) um inteiro chamado number.


(b) um inteiro longo chamado lnum.
(c) um real de precisão simples chamado x.
(d) um real de precisão dupla chamado xd.
(e) uma string chamada hello.

3. Crie um programa que faça o mesmo que a questão anterior e, em seguida,


para cada variável, imprima uma mensagem com seu nome, a palavra
”vale”, e seu valor. Para uma variável chamada pipoca, por exemplo:
pipoca = 3.141592
PRINT " pipoca vale " ; pipoca

pipoca vale 3.141592

4. Crie um programa que calcule e imprima o fatorial de

(a) 2.
(b) 3.
(c) 4.
(d) 5.

5. Crie um programa que calcule e imprima a soma dos inteiros menores ou


iguais a

(a) 2.
(b) 3.
(c) 4.
(d) 5.

26
6. Crie um programa que calcule e imprima a área das figuras planas especi-
ficadas. Para um paralelogramo com lados 10 e 4, com ângulo de 60 graus
entre eles, por exemplo:
pi = 3.141592#
l1 = 10
l2 = 4
deg = 60
h = l2 * SIN ( deg * pi / 180)
area = l1 * h
PRINT " area = " ; area

area = 20

(a) um retângulo com lados 3 e 6.


(b) um quadrado com lado 5.
(c) um triângulo retângulo com catetos 3 e 4.
(d) um triângulo retângulo com cateto igual a 5 e hipotenusa igual a 13.
(e) um triângulo equilátero com lado 4.
(f) um cı́rculo com raio 2.

7. Crie um programa que calcule e imprima o volume dos sólidos especifica-


dos.
(a) um cubo com aresta igual a 5.
(b) um paralelepı́pedo com lados 3, 4 e 5.
(c) um cilindro cuja base tem raio igual a 3 e altura igual a 4.
(d) uma pirâmide com base quadrada de lado 5 e altura igual a 6.
(e) uma esfera com raio igual a 1.
(f) um prisma cuja base é um triângulo equilátero com lado igual a 2 e
altura igual a 10.
8. Considere um material com densidade de 0.420 g/cm3 . Crie um programa
que calcule e imprima a massa em g e kg dos objetos descritos abaixo.
(a) uma folha de 19 × 270 cm e espessura de 0.6 mm.
(b) uma chapa de 210 × 82 cm e espessura de 3.5 cm.
(c) uma ripa de 1 × 2 cm e comprimento de 1.2 m.
(d) um sarrafo de 3.5 × 4 cm e comprimento de 3 m.
(e) um caibro de 5 × 5 cm e comprimento de 3 m.

27
(f) uma viga de 4 × 9 cm e comprimento de 4 m.
(g) um tarugo com diâmetro de 15 mm e comprimento de 60 cm.
9. Considere os vetores v = (2, 2, 0) e w = (3, −3, 0). Crie um programa que
calcule e imprima

(a) o vetor v + w.
(b) o vetor v − w.
(c) a norma de v.
(d) a norma de w.
(e) o coeficiente angular de v, i.e. o ângulo formado entre o vetor e o
eixo x.
(f) o coeficiente angular de w.
(g) o produto escalar de v por w.
(h) o produto vetorial de v por w.

10. Considere a equação de segundo grau x2 − 3x − 10 = y. Crie um programa


que calcule e imprima
(a) o valor de ∆ = b2 − 4ac.

(b) suas duas raı́zes reais, dadas por x = (−b ± ∆)/2a.
(c) a coordenada x do vértice, dada por x = −b/2a.
(d) a coordenada y do vértice, dada por y = −∆/4a.
11. Sabendo que loga b = log b/ log a, crie um programa que calcule e imprima
(a) o valor de log2 1024.
(b) o valor de log3 729.
(c) o valor de log4 256.
(d) o valor de log5 625.
12. Crie um programa que imprima em uma tabela os valores de 0 a 100
graus Celsius em intervalos de 10 graus na primeira coluna. Na segunda
coluna imprima os valores correspondentes em Kelvin e na terceira, os
valores correspondentes em Fahrenheit. Seja c o valor em Celsius, k o
valor em Kelvin e f o valor em Fahrenheit, considere que k = c + 273.15 e
f = c × 9/5 + 32.

28
Capı́tulo 2

Controle de fluxo

Um programa de computador é uma sequência de instruções. Normalmente as


instruções são executadas na ordem em que aparecem no programa. Porém, isso
permite apenas a criação de programas muito simples.
Imagine que tenhamos por exemplo uma matriz com centenas de valores.
Para processar cada item dessa matriz, precisamos executar centenas de ins-
truções. Se a instrução for a mesma para todos os itens da matriz, podemos
facilitar nossa vida criando um programa bem mais simples se colocarmos essa
instrução dentro de um laço, ao invés de ter uma cópia desta mesma instrução
para cada item da matriz.
Outro caso em que o controle de fluxo é útil é quando uma instrução é
executada em apenas alguns casos. Imagine que temos um banco de dados com
milhões de valores de CPF e queremos imprimir apenas o nome do portador de
um certo CPF. Podemos usar uma instrução do tipo IF que, para cada CPF
lido, testa se é igual ao CPF desejado e imprime o nome do portador somente
em caso afirmativo.

2.1 Saltos condicionais


O objetivo de uma instrução de salto condicional é executar um bloco de ins-
truções caso uma condição seja satisfeita. Caso contrário, ou seja, caso a
condição não seja satisfeita, é feito um salto e o bloco não é executado. As
funções de salto condicional são IF e SELECT.

2.1.1 Instrução IF
A sintaxe do salto condicional com as instruções IF...THEN...END IF é a seguinte:
IF b oo le an _e xp re ss io n THEN
[ block_then ]
END IF

29
Caso boolean_expression retorne um valor verdadeiro, o bloco de ins-
truções block_then é executado. Abaixo está um exemplo de uso de salto
condicional. O programa solicita ao usuário que insira sua idade. Caso ela seja
menor que zero, a mensagem de aviso é impressa na tela.
INPUT " Digite sua idade : " , idade &
IF idade & < 0 THEN
PRINT " Aviso : sua idade deve ser >= 0. "
END IF

É possı́vel usar também expressões de comparação com strings.


INPUT " Digite seu nome : " , nome$
IF nome$ = " " THEN
PRINT " Aviso : nome curto demais . "
END IF

Opcionalmente, é possı́vel definir um bloco de instruções que é executado


caso a condição seja falsa. Isso é feito com a instrução ELSE.
IF b oo le an _e xp re ss io n THEN
[ block_then ]
[ ELSE
[ block_else ]]
END IF

Abaixo está um exemplo de uso de salto condicional com ELSE. O programa


solicita ao usuário que insira um número inteiro. O programa então indica se o
número é par ou ı́mpar.
INPUT " Digite um inteiro " , num &
IF num & MOD 2 = 1 THEN
PRINT num &; " eh impar . "
ELSE
PRINT num &; " eh par . "
END IF

30
Outro formato do salto condicional permite o teste de várias condições. Isso
é feito com a instrução ELSEIF.
IF b o o l e a n _ e x p r e s s i o n _ 1 THEN
[ block_1 ]
[ ELSEIF b o o l e a n _ e x p r e s s i o n _ 2 THEN
[ block_2 ]]
...
[ ELSE
[ block_else ]]
END IF

Abaixo está um exemplo de salto condicional com ELSEIF. O programa so-


licita ao usuário que insira um número inteiro entre 0 e 999. O programa então
indica quantos dı́gitos o número possui.
INPUT " Digite um inteiro de 0 a 999: " , num &
IF num & < 0 OR num & > 999 THEN
PRINT num &; " esta fora do intervalo permitido . "
ELSEIF num & < 10 THEN
PRINT num &; " possui 1 digito . "
ELSEIF num & < 100 THEN
PRINT num &; " possui 2 digitos . "
ELSE
PRINT num &; " possui 3 digitos . "
END IF

2.1.2 Instrução SELECT


A instrução SELECT seleciona um bloco de instruções a ser executado em função
do valor de uma expressão. A sintaxe do salto condicional com as instruções
SELECT case...END SELECT é a seguinte:
SELECT CASE test_expression
[ CASE expre ssion_ list_1 ]
[ block_1 ]
[ CASE expre ssion_ list_2 ]
[ block_2 ]
...
[ CASE ELSE ]
[ block_else ]
END SELECT

31
A expressão test_expression pode ter tipo numérico ou string. Cada uma
das expression_list é uma lista de uma ou mais expressões de mesmo tipo
que test_expression separadas por vı́rgula. Caso o valor de test_expression
corresponda ao valor de uma das expression_list, o bloco de instruções cor-
respondente é executado. Caso não corresponda, block_else é executado. As
expressões devem possuir a sintaxe abaixo.

expression [ , expression ...]


expression TO expression
IS { <| <=| >| >=| < >|=} expression

O primeiro caso enumera os valores que test_expression deve assumir para


se executar o bloco correspondente. O segundo define um intervalo. O terceiro
define uma condição com os operadores relacionais. Abaixo está um exemplo
de uso de SELECT. O programa solicita ao usuário que insira uma nota de 0 a
10 e imprime uma mensagem em função da nota inserida. Observe que a nota
8 ocorre em duas condições diferentes. Nesse caso, apenas o bloco da primeira
condição selecionada é executado.

INPUT " Digite sua nota de 0 a 10: " , nota


nota = INT ( nota )
PRINT " Nota " ; nota ;
SELECT CASE nota
CASE 10
PRINT " Parabens , voce tirou a nota maxima ! "
CASE 8 , 9
PRINT " Parabens , voce tirou uma otima nota ! "
CASE 6 , 7 , 8
PRINT " Meh , voce tirou uma nota marroumenos ... " ;
CASE 5
PRINT " Passou raspando . "
CASE 1 TO 4
PRINT " Reprovado . Mais sorte na proxima ... "
CASE 0
PRINT " Sem comentarios ... "
CASE IS > 20 , IS < 0
PRINT " Nota invalida . "
CASE ELSE
PRINT " Como conseguiu ? "
END SELECT

32
2.2 Laços
Um laço é uma instrução que executa um bloco repetidas vezes. É possı́vel exe-
cutar um bloco um número predefinido de vezes ou enquanto alguma condição
seja satisfeita.

2.2.1 Instrução FOR


Quando queremos executar um bloco de instruções um número predefinido de
vezes, tipicamente usamos a instrução FOR...NEXT. Sua sintaxe é a seguinte:
FOR counter = start TO end [ STEP increment ]
[ block ]
NEXT counter

O laço FOR inicializa counter com valor igual a start. A cada execução
de block, counter por padrão é incrementado de 1. O laço termina quando
counter atinge o valor de end. Caso a instrução opcional STEP seja usada, o
incremento ao invés de 1 é dado por increment. O incremento pode também
ser negativo, mas nesse caso, end precisa ser menor que start.
O exemplo abaixo imprime os inteiros de 1 a 10.
FOR i = 1 TO 10
print i
NEXT i

Caso queiramos os inteiros de 0 a 100 múltiplos de 10, podemos usar um


incremento de 10.
FOR i = 0 TO 100 STEP 10
print i
NEXT i

Abaixo está um exemplo com incremento negativo.


FOR i = 0 TO -20 STEP -2
print i
NEXT i

Um exemplo tı́pico do uso do FOR é o cálculo de uma série, ou seja, a so-


matória dos valores de uma sequência. Para somar os inteiros de 1 a 10, ou seja,
10
∑i=1 i, podemos usar o código abaixo.

33
s = 0
FOR i = 1 TO 10
s = s + i
NEXT i
PRINT " A somatoria eh " , s

Outro exemplo de uso do FOR é o cálculo de um produtório, como por exem-


plo, o fatorial de um número inteiro. Para calcular o fatorial de 10, ou seja,
10
∏i=1 i, podemos usar o código abaixo.
p = 1
FOR i = 1 TO 10
p = p * i
NEXT i
PRINT " O produtorio eh " , p

Caso seja necessário finalizar o laço prematuramente, a instrução EXIT FOR


pode ser usada.
EXIT FOR

2.2.2 Instrução WHILE...WEND


Quando queremos executar um bloco de instruções enquanto uma certa condição
de continuidade é satisfeita, usamos a instrução WHILE...WEND. Sua sintaxe é a
seguinte:
WHILE condition
[ block ]
WEND

Todos os exemplos vistos anteriormente com a instrução FOR podem ser


reescritos com o WHILE. Porém, a inicialização e o incremento do contador devem
ser feitos manualmente. Abaixo está o exemplo que imprime os inteiros de 1 a
10.
i = 1 ’ Inicializacao
WHILE i <= 10
PRINT i
i = i + 1 ’ Incremento
WEND

34
Abaixo está o exemplo que calcula a soma dos inteiros de 1 a 10.
s = 0
i = 1 ’ Inicializacao
WHILE i <= 10
s = s + i
i = i + 1 ’ Incremento
WEND
PRINT s

Abaixo está o exemplo que calcula o fatorial de 10.


p = 1
i = 1 ’ Inicializacao
WHILE i <= 10
p = p * i
i = i + 1 ’ Incremento
WEND
PRINT p

Um exemplo mais interessante que não é uma conversão direta de um uso


tı́pico do FOR é o seguinte. Considere a série geométrica abaixo.


1
∑ i
=2
i=0 2

Se quiséssemos somar as infinitas parcelas da somatória, o programa não


terminaria nunca. Uma alternativa razoável para estimar o valor da somatória
é somar enquanto as parcelas são maiores do que um certo ε suficientemente
pequeno.
epsilon = 10 ^ -20
s# = 0
i = 0 ’ Inicializacao
parcela = 1 / 2 ^ i
WHILE parcela > epsilon
s # = s # + parcela
PRINT i , parcela , s #
i = i + 1 ’ Incremento
parcela = 1 / 2 ^ i
WEND
PRINT i , parcela

35
2.2.3 Instrução DO...LOOP
A instrução DO...LOOP é ainda mais flexı́vel que WHILE...WEND. Ela permite que o
teste da condição de continuidade seja feito no inı́cio ou no final do laço. Sua
sintaxe equivalente a WHILE...WEND é a seguinte:
DO WHILE condition
[ block ]
LOOP

O código abaixo é equivalente ao do último exemplo visto, mas foi reescrito


com a instrução DO...LOOP.
epsilon = 10 ^ -20
s# = 0
i = 0 ’ Inicializacao
parcela = 1 / 2 ^ i
DO WHILE parcela > epsilon
s # = s # + parcela
PRINT i , parcela , s #
i = i + 1 ’ Incremento
parcela = 1 / 2 ^ i
LOOP
PRINT i , parcela

Sua sintaxe alternativa, que testa a condição ao final da execução do laço é


a seguinte:
DO
[ block ]
LOOP WHILE condition

Esta última sintaxe pode ser conveniente quando precisamos que o laço seja
executado ao menos uma vez. No último exemplo visto, é possı́vel observar
que o cálculo de parcela ocorre em duas linhas de código diferentes. Pode ser
interessante eliminar essa redundância para evitar inconsistências e erros. Isso
é possı́vel se deixarmos para testar a condição no final do laço.

36
epsilon = 10 ^ -20
s# = 0
i = 0 ’ Inicializacao
DO
parcela = 1 / 2 ^ i
s # = s # + parcela
PRINT i , parcela , s #
i = i + 1 ’ Incremento
LOOP WHILE parcela > epsilon
PRINT i , parcela

Outra possibilidade da instrução DO...LOOP é, ao invés de testar uma condição


de continuidade com WHILE, testar uma condição de parada com UNTIL. Nesse
caso, sua sintaxe é a seguinte:
DO UNTIL condition
[ block ]
LOOP

Alternativamente, podemos testar a condição de parada ao final do laço.


DO
[ block ]
LOOP UNTIL condition

Abaixo está o último exemplo reescrito com UNTIL.


epsilon = 10 ^ -20
s# = 0
i = 0 ’ Inicializacao
DO
parcela = 1 / 2 ^ i
s # = s # + parcela
PRINT i , parcela , s #
i = i + 1 ’ Incremento
LOOP UNTIL parcela < epsilon
PRINT i , parcela

Caso seja necessário finalizar o laço prematuramente, a instrução EXIT DO


pode ser usada.
EXIT DO

37
2.3 Exercı́cios
1. Crie um programa que calcula com um laço o produtório abaixo para
n = 10.
(a)
n
∏ i = n!
i=1

2. Refaça a questão anterior pedindo ao usuário que forneça um valor de n.


3. Crie um programa que calcula as séries abaixo para n = 10. Calcule a
somatória com um laço. Caltule também o lado direito da equação e
imprima ambos os resultados para comparação.
(a)
n
n(n + 1)
∑i =
i=1 2
(b)
n
∑ 2i = n + n
2
i=1

(c)
n
∑ 2i − 1 = n
2
i=1

(d)
n
∑2 = 2 −1
i n+1
i=0

(e)
n
1
∑ i = n(n + 1)(2n + 1)
2
i=1 6
(f)
2
n
n(n + 1)
∑i = ( )
3
i=1 2
(g)
n
i n
∑ =
i=1 i + 1 n+1
(h)
n
n(3n − 1)
∑ 3i − 2 =
i=1 2
(i)
n
n(10 + 2(n − 1))
∑ 5 + 2(i − 1) =
i=1 2

38
(j)
n
∑ i(2)
i−1
= 1 + (n − 1)2n
i=1

(k)
n
1
lim ∑ =e
n→∞
k=0 k!
(l)
n
(−1)k π
lim ∑ =
k=0 2k + 1 4
n→∞

(m)
m n
mn(m + 1)(n + 1)
∑ ∑ ij =
i=1 j=1 4

4. Refaça a questão anterior pedindo ao usuário que forneça um valor de n.


5. Crie um programa que calcula a soma dos 100 primeiros termos das séries
abaixo.
(a)

1

i=0 i

(b)

1
∑ i
i=0 2
6. Crie um programa que calcula as séries da questão anterior enquanto a
parcela é maior que 10− 3.
7. Uma relação de recorrência é uma equação segundo a qual o n-ésimo termo
de uma sequência é dado por alguma combinação dos termos anteriores.
O método de Newton é um exemplo de relação de recorrência.

f (xn )
xn+1 = xn −
f ′ (xn )

O processo é repetido até que o valor de f (xn ) seja suficientemente próximo


de zero, ou seja, até que tenha módulo menor que um certo erro ε. Use o
método de Newton para encontrar
(a) duas raı́zes de f (x) = x2 − 9.
(b) duas raı́zes de f (x) = x2 + x − 2.
(c) uma raı́z de cos(x) entre 0 e 3.
8. Crie um programa que calcula o produto dos 100 primeiros termos dos
produtórios abaixo.

39
(a)

2k 2k 224466 π
∏( )= =
k=1 2k − 1 2k + 1 133557 4
9. O número de combinações de n itens k a k é dado pela equação abaixo.
n n!
( )=
k k!(n − k)!

(a) Peça ao usuário que insira n e k. Use-os para calcular (nk).


(b) Faça dois laços e imprima as dez primeiras linhas do triângulo de
Pascal, ou seja, para cada linha n de 0 a 9, imprima os valores de (nk)
com k de 0 a n.

10. Crie um programa que testa se um certo n é primo. Use um laço para
testar se os inteiros menores que n o dividem.
(a) Teste para n = 101.
(b) Solicite para o usuário que insira algum valor de n.
(c) Teste para n variando de 2 a 1000 e imprima o total de números
primos encontrados.
(d) Teste para n variando de 3 a 9999 pulando os pares e imprima o total
de números primos encontrados.

40
Capı́tulo 3

Tipos de dados compostos

Nem todos os problemas podem ser resolvidos com variáveis simples como as
primitivas já vistas. Bancos de dados requerem o uso de registros com cam-
pos diferentes para armazenar por exemplo o nome, endereço, estado civil etc
de cada cliente. Problemas que envolvem matrizes, vetores, listas e sequências
requerem o uso de estruturas indexadas, ou seja, que permitam acessar compo-
nentes individuais através de ı́ndices inteiros. Neste capı́tulo veremos como criar,
modificar e consultar estruturas com tipos de dados compostos, que podem ser
homogêneas, compostas por itens de mesmo tipo, ou heterogêneas, compostas
por itens de tipos diferentes.

3.1 Estruturas compostas homogêneas


As estruturas compostas homogêneas são chamadas arrays e são usadas para
representar vetores e matrizes. Vetores são representados por arrays unidimen-
sionais e matrizes por arrays bidimensionais. O número de dimensões de um
array é dado pelo número de ı́ndices usados para acessar uma posição. Também
é possı́vel se necessário ter mais dimensões. O número de posições possı́veis de
cada dimensão é seu tamanho.
Um vetor com três coordenadas é então representado por um array com
uma dimensão de tamanho três. Uma matriz com três linhas e quatro colunas
é representada por um array bidimensional com dimensões de tamanho três e
quatro.
Abaixo está a sintaxe da declaração de um array.
DIM variable ( [ lower TO ] upper
[ , [ lower TO ] upper ]...) [ AS TYPE ]

O tamanho ou as posições válidas de cada dimensão vão de lower até upper.


O valor de lower é opcional e quando omitido é zero. A cada nova dimensão,

41
novos valores de lower e upper devem ser adicionados separados por vı́rgula
dentro dos parênteses. Abaixo estão exemplos de declarações de arrays.
DIM array (1 TO 3) AS DOUBLE ’ Vetor com tres posicoes
DIM matrix (2 , 4) AS SINGLE ’ Matriz 3 x5
DIM mat3 (4 , 5 , 6) AS LONG ’ Volume tridimensional

Para modificar ou consultar uma posição de um array, a sintaxe é a mesma


de uma variável, com a diferença de que o ı́ndice da posição desejada deve ser
colocado entre parênteses depois do nome do array. É necessária uma tupla de
ı́ndices com mesmo número de valores que o número de dimensões do array.
Abaixo estão exemplos de como acessar posições dos arrays.
p = 2
array (1) = 10.0 ’ Modificando posicao 1
array ( p ) = 1/3 ’ Modificando posicao dada por p
n = array (1) ’ Consultando posicao 1
matrix (0 , 0) = 5 ’ Modificando posicao (0 , 0)
matrix (1 , p ) = 6 ’ Modificando posicao (1 , p )
n = matrix (0 , 0) ’ Consultando posicao (0 , 0)
m = matrix (1 , p ) ’ Consultando posicao (1 , p )

É possı́vel consultar o tamanho das dimensões individuais de um array. Isso


é útil para tornar as funções mais flexı́veis e eliminar a necessidade de passar o
tamanho como parâmetro. Abaixo está um exemplo de como fazer isso no array
bidimensional matrix.
FOR d = 1 TO 2
PRINT USING " dim ## from ### to ### " ; d ;
LBOUND ( array , d ) ; UBOUND ( array , d )
NEXT d

3.2 Estruturas compostas heterogêneas


As estruturas compostas homogêneas são também chamadas de registros. São
úteis na criação de bancos de dados e podem armazenar em conjunto dados
numéricos e de texto. Quando vários registros de mesmo tipo são necessários,
podem ser armazenados como posições individuais em um vetor. Abaixo está a
sintaxe da criação de um tipo de dados de registro definido pelo usuário.

42
TYPE user_type
item_name as item_type
[ item_name as item_type ]
...
END TYPE

O nome do tipo de dados é dado por user_type. O nome dos itens indi-
viduais é dado por cada um dos item_name. Os tipos permitidos são os tipos
de dados primitivos ou algum outro tipo definido pelo usuário. Quando o tipo
é STRING, sua definição é feita com STRING * n onde n é o tamanho máximo
permitido da STRING. Abaixo está o exemplo de criação de dois tipos de registro
diferentes.
TYPE Date
day AS INTEGER
month AS INTEGER
year AS INTEGER
END TYPE

TYPE Customer
cname AS STRING * 10
address AS STRING * 20
city AS STRING * 10
state AS STRING * 2
birth AS Date
END TYPE

Abaixo está um exemplo de como acessar os registros. Na primeira linha


está a a locação da variável entry com o tipo de dados composto Customer.
Cada item do registro é acessado através do nome da variável seguido de ponto
e o nome do item desejado.
DIM entry AS Customer
INPUT " Customer name : " ; entry . cname
INPUT " Customer addr : " ; entry . address
INPUT " Customer city : " ; entry . city
INPUT " Customer stat : " ; entry . state
INPUT " Customer birth year : " ; entry . birth . year
INPUT " Customer birth month : " ; entry . birth . month
INPUT " Customer birth day : " ; entry . birth . day

Para declarar um array de registros e acessar alguma de suas entradas, a


sintaxe é a mesma de um array comum.

43
DIM arrEntry (10) AS Customer
arrEntry (0) = entry
DIM e AS Customer
e = arrEntry (0)

3.3 Exercı́cios
1. Crie um tipo de dados chamado TAluno com os seguintes campos: id com
tipo LONG, nome com tipo STRING de tamanho 20, matricula com tipo
string de tamanho 12, e os campos dianasc, mesnasc e anonasc com tipo
INTEGER. Com esse tipo de dados
(a) crie uma variável chamada umAluno de tipo TAluno.
(b) crie um array chamado arrAluno com ı́ndices de 1 a 10 e de tipo
TAluno.
(c) crie um laço que solicita ao usuário que preencha o vetor arrAluno.
O laço é interrompido quando algum aluno tiver nome vazio.
2. Crie um programa que aloca um array com tamanho 4×10. Use o array
para armazenar os valores abaixo considerando x variando de 1 a 10.

(a) Na primeira coluna o valor de x.


(b) Na segunda coluna o valor de x2 .
(c) Na terceira coluna o valor de x3 .
(d) Na quarta coluna o valor de x4 .
(e) Imprima o conteúdo do array.

3. Crie um programa que testa se um certo n é primo. Armazene os primos


encontrados em um vetor. Use um laço para testar se os primos armaze-
nados no vetor dividem n.
(a) Teste para n = 101.
(b) Solicite para o usuário que insira algum valor de n.
(c) Teste para n variando de 2 a 1000 e imprima o total de números
primos encontrados.
(d) Teste para n variando de 3 a 9999 pulando os pares e imprima o total
de números primos encontrados.
(e) Use TIMER para cronometrar o tempo de processamento. Compare
com a versão do programa do capı́tulo anterior.

44
Capı́tulo 4

Funções e procedimentos

Muitas vezes é necessário reutilizar código escrito previamente. Simplesmente


copiar o código de outra parte do programa pode não ser uma boa polı́tica, pois
qualquer modificação ou correção que for necessária deve ser feita em todas as
ocorrências do código, dificultando a manutenção. Nesse caso é recomendável
usar uma função ou procedimento.
Uma chamada de função deve retornar um valor, e pode ser usada como uma
expressão com mesmo tipo de dado de seu valor de retorno. Já um procedimento
não retorna um valor, portanto não pode ser usado em uma expressão. Em
ambos os casos, os parâmetros são passados por referência. Isso significa que se
uma certa variável é passada como parâmetro e se o parâmetro for modificado
dentro da função ou procedimento, a variável original também é alterada no seu
escopo original. É necessário então ter cuidado e nunca alterar os valores dos
parâmetros sem necessidade.

4.1 Funções
Funções são blocos de instruções que executam uma certa tarefa. Recebem
parâmetros de entrada, retornam dados de saı́da e sua chamada pode ser usada
em expressões.
Podemos dizer que a definição de uma função tem quatro partes: identifi-
cador ou nome, lista de parâmetros, bloco de instruções e valor de retorno. A
sintaxe de uma definição de função é a seguinde:
FUNCTION name [( parameter_list ) ][ STATIC ]
[ statements ]
name = expression
[ statements ]
END FUNCTION

45
O nome da função é dado por name. A função retorna um valor através da
atribuição do valor de uma expressão ao nome da função. O uso do keyword
opcional STATIC faz com que os valores das variáveis da função sejam mantidos
entre as chamadas. Os parâmetros são passados por referência, ou seja, se
forem modificados dentro da função, serão modificados também fora do escopo
da função. A lista parameter list possui a sintaxe abaixo:
variable [ AS type ][ , variable [ AS type ]]...

Abaixo está um exemplo de uma função simples que calcula o volume de


uma caixa com os lados passados como parâmetro.
FUNCTION volumeCaixa (a , b , c )
volumeCaixa = a * b * c
END FUNCTION

Abaixo está um exemplo de uma função que calcula o volume de um cilindro


com raio r e altura h.
FUNCTION volumeCilindro (r , h )
base = 3.141592 * r * r
volumeCilindro = base * h
END FUNCTION

Abaixo está um exemplo de uma função que calcula o fatorial de n.


FUNCTION fatorial ( n )
p = 1
FOR i = 2 TO n
p = p * i
NEXT i
fatorial = p
END FUNCTION

Para chamar uma função, é preciso criar uma expressão onde seu nome
precede a lista de parâmetros entre parênteses. Os parâmetros também são
expressões, e podem ser literais, variáveis, operações com outras expressões ou
até mesmo chamadas a outras funções.

46
v = 5
PRINT fatorial (4) ’ Parametro como literal
PRINT fatorial ( v ) ’ Parametro como variavel
PRINT fatorial ( v + 1) ’ Parametro como expressao
PRINT fatorial ( SQR (16) ) ’ Parametro como chamada
result1 = fatorial ( v + 2) ’ Resultado em atribuicao
result2 = 3 * fatorial ( v ) ’ Resultado em expressao

4.2 Procedimentos
Procedimentos são também chamados subrotinas. Os procedimentos, assim
como funções, são blocos de instruções e recebem parâmetros de entrada. Ao
contrário das funções, porém, não retornam dados de saı́da e sua chamada não
pode ser usada em expressões.
A definição de um procedimento é praticamente igual à de uma função. As
diferenças estão no uso da palavra chave SUB e na ausência de atribuição de um
valor de retorno. A sintaxe de uma definição de procedimento é a seguinde:
SUM name [( parameter_list ) ][ STATIC ]
[ statements ]
END SUB

O nome do procedimento é dado por name. O uso do keyword opcional


STATIC faz com que os valores das variáveis do procedimento sejam mantidos
entre as chamadas. Os parâmetros são passados por referência, ou seja, se
forem modificados dentro da função, serão modificados também fora do escopo
da função. A lista parameter list possui a sintaxe abaixo:
variable [ AS type ][ , variable [ AS type ]]...

Uma chamada a subrotina não pode fazer parte de uma expressão. A sintaxe
da chamada a uma subrotina é a seguinte
CALL name ( parameter_list )

Abaixo está um exemplo de procedimento que calcula e imprime uma men-


sagem com o volume de uma caixa com os lados passados como parâmetro.
SUB printVolume (a , b , c )
PRINT " O volume da caixa eh " ; a * b * c
END SUB

47
Outro possı́vel uso de um procedimento é quando precisamos retornar vários
valores simultaneamente. Nesse caso, os valores de retorno são passados como
parâmetros e são modificados dentro do procedimento. Abaixo está um exemplo
de procedimento que calcula a soma de dois vetores bidimensionais e retorna os
valores dos dois componentes de saida como s1 e s2.
SUB somaV2 ( a1 , a2 , b1 , b2 , s1 , s2 )
s1 = a1 + b1
s2 = a2 + b2
END SUB

Abaixo está a chamada ao procedimento somaV2. Observe os valores de x e


y antes e depois da chamada ao procedimento.
PRINT x , y
CALL somaV2 (1 , 2 , 3 , 4 , x , y )
PRINT x , y

Abaixo está a saı́da do código anterior.


0 0
4 6

4.3 Recursividade
Uma função recursiva é uma função que chama a si mesma. Toda recursão
precisa ter uma base, ou seja, um caso de parada. Considere a definição do
fatorial. O fatorial pode ser definido como na equação abaixo.

n
n! = ∏ i
i=1

Alternativamente, podemos definir o fatorial de forma recursiva



⎪(n − 1)! se n > 1
n! = ⎨

⎪1 se n ≤ 1

Quando n > 1 a função chama ela mesma passando como parâmetro n − 1. O
caso base desta recursão é o caso em que n ≤ 1. Quando o parâmetro de entrada
n é igual a 1 por exemplo, a função retorna sem fazer chamadas adicionais.
Abaixo está um exemplo de uma função recursiva que calcula o fatorial de n.

48
FUNCTION fatorial ( n )
IF n <= 1 THEN
fatorial = 1
ELSE
fatorial = n * fatorial ( n - 1)
END IF
END FUNCTION

4.4 Arrays como parâmetros


Para passar valores individuais de um array como parâmetro para uma função
ou procedimento, basta usar o nome do array seguido do ı́ndice da posição
desejada como se referenciaria esse valor normalmente em uma expressão.
Para passar o vetor array, porém, é necessário tomar cuidado pois a sintaxe
é um pouco diferente. O exemplo abaixo mostra como fazer isso. Na chamada
é necessário usar o nome do array seguido de abre e fecha parênteses. Na
declaração da função, é necessário explicitar que aquele parâmetro é um vetor
usando abre e fecha parênteses, a palavra AS e o tipo de dados do array.
size = 10
DIM arr ( size ) AS INTEGER
CALL change ( arr () , size )
for idx = 1 to size
PRINT arr ( idx )
NEXT idx

SUB change ( a () AS INTEGER , n )


FOR i = 1 TO n
a ( i ) = 10 * i
NEXT i
END SUB

4.5 Exercı́cios
1. A sequência de Fibonacci é definida pela relação de recorrência abaixo.


⎪F0 = 0



⎨F1 = 1




⎩Fn = Fn−1 + Fn−2 se n > 1
Crie um programa que pede ao usuário um valor de n e calcula a sequência
de Fibonacci de F0 até Fn usando uma função recursiva.

49
2. Para cada série das questões 3 e 5 do capı́tulo anterior, escreva uma função
que recebe n como parâmetro e que calcula a somatória até n
(a) de maneira iterativa, ou seja, com um laço.
(b) de maneira recursiva, ou seja, chamando a própria função.

3. Crie a função
(a) logab(a, b) que calcula e retorna loga b.
(b) atan2(x, y) que calcula e retorna o arco tangente do ângulo formado
pelo vetor (x, y) e o eixo x. O resultado deve estar no intervalo
(−π, π].

4. Considere que os vetores abaixo são arrays com duas posições. Crie uma
função
(a) norma(v) que retorna a norma de v.
(b) ang(v) que retorna o coeficiente angular de v.
(c) soma(v, w) que retorna a soma de v e w.
(d) prodEsc(v, w) que retorna o produto escalar entre v e w.
v⋅w
(e) proj(v, w) que retorna a projeção de v sobre w, ou seja, w⋅w
w.
5. Considere que os números complexos abaixo são representados como ar-
rays com duas posições. Crie uma função

(a) r(z) que retorna o valor absoluto do número complexo z.


(b) phi(z) que retorna o ângulo correspondente à forma polar do número
complexo z.
(c) somaC(z, w) que retorna o número complexo igual à soma z + w.
(d) prodC(z, w) que retorna o número complexo igual ao produto zw.
6. Implemente um Conway’s Game of Life. Declare duas matrizes com ta-
manho 20×40. Crie uma função
(a) init(mat()) que inicializa a matriz com valores 0 ou 1 aleatoria-
mente.
(b) prt(mat()) que imprime o conteúdo da matriz na tela.
(c) iter(mat0(), mat1()) que gera mat1 em função de mat0 conforme
a regra a seguir: caso a posição (i, j) de mat0 tenha três ou quatro
vizinhos iguais a 1, a mesma posição de mat1 recebe 1, caso contrário
recebe 0.
(d) run(n) que chama init para inicializar mat0 e em seguida chama
iter n vezes, na primeira vez sobre o resultado de init, nas demais
vezes sobre o resultado da própria iter.

50
Capı́tulo 5

Som e gráficos

Neste capı́tulo veremos como usar o QBasic para produzir sons e saı́da gráfica.

5.1 Som
Nesta seção descrevemos algumas instruções que podem ser usadas para gerar
sons no QBasic. A Tabela 5.1 lista as funções descritas nesta seção. As funções
iniciadas com sublinhado são exclusivas do QB64.

Tabela 5.1: Funções para saı́da de áudio

Operação Função
Emite som de bipe BEEP
Som com certa frequência e duração SOUND
Notas definidas em string PLAY
Abre arquivo com som _SndOpen
Toca som salvo em variável _SndPlay
Toca som gerado por função _SndRaw
Pausa _Delay

O código abaixo emite um bipe, que pode ser usado para alertar o usuário.
BEEP

Abaixo está a sintaxe da instrução SOUND. O valor da expressão frequency


indica a frequência da onda sonora e deve ser de 37 a 32767. O valor da expressão
duration indica o número de intervalos de 1/18 segundos que o som deve durar.
SOUND frequency , duration

51
O código abaixo toca duas vezes o primeiro compasso do Prelúdio em Dó
Maior de Bach.
c = 262 ’ C4
r1 = 1.26 ’ terca
r2 = 1.5 ’ quinta
r = 2 ’ oitava acima
t = 3 ’ 3/18 segundos
FOR i = 1 TO 4
SOUND c , t ’ C4
SOUND c * r1 , t ’ E4
SOUND c * r2 , t ’ G4
SOUND c * r , t ’ C5
SOUND c * r * r1 , t ’ E5
SOUND c * r2 , t ’ G4
SOUND c * r , t ’ C5
SOUND c * r * r1 , t ’ E5
NEXT i

O código abaixo faz um glissando subindo e descendo.


FOR x = 38 To 1000 STEP 2
SOUND x , .05
NEXT x
FOR x = 1000 TO 38 STEP -2
SOUND x , .05
NEXT x

Abaixo está a sintaxe da instrução PLAY. O parâmetro string indica as


notas a serem tocadas e suas durações conforme a especificação dos comandos
musicais descrita na Tabela 5.2
PLAY string

O código abaixo mostra um exemplo de uso da instrução PLAY.


PLAY " L16 T110 O2 "
c1$ = " CEG > CE <G > CE < "
PLAY c1$ + c1$
c2$ = " CDA > DF <A > DF < "
PLAY c2$ + c2$
c3$ = " <B > DG > DF <G > DF < "
PLAY c3$ + c3$
PLAY c1$ + c1$

52
Tabela 5.2: Comandos musicais para a instrução PLAY.

Descrição Comando
Especifica oitava (n = 0-6) On
Desce uma oitava <
Sobe uma oitava >
Toca notas (A = Lá, B = Si,...,G = Sol) A-G
Sustenido +
Bemol -
Toca notas (n = 0-84) Nn
Quartos de nota por minuto (n = 32-255, padrão = 120) Tn
Define duração (n = 1-64, duração = 1/n) Ln
Duração de 3/4 da definida por L MS
Duração de 7/8 da definida por L MN
Retorna à duração definida por L ML
Pausa de n quartos de nota (n = 1-64) Pn
Toca música em foreground MF
Toca música em background MB

Tabela 5.3: Notas da instrução PLAY e frequências correspondentes da instrução


SOUND.

8a Nota Freq. 8a Nota Freq. 8a Nota Freq. 8a Nota Freq.


C 1 12,C 131 3 36,C 523 5 60,C 2093
C# 1 13,C# 139 3 37,C# 554 5 61,C# 2217
D 1 14,D 147 3 38,D 587 5 62,D 2349
D# 39 1 15,D# 156 3 39,D# 622 5 63,D# 2489
E 41 1 16,E 165 3 40,E 659 5 64,E 2637
F 44 1 17,F 175 3 41,F 698 5 65,F 2794
F# 46 1 18,F# 185 3 42,F# 740 5 66,F# 2960
G 49 1 19,G 196 3 43,G 784 5 67,G 3136
G# 51 1 20,G# 208 3 44,G# 831 5 68,G# 3322
A 55 1 21,A 220 3 45,A 880 5 69,A 3520
A# 58 1 22,A# 233 3 46,A# 932 5 70,A# 3729
B 62 1 23,B 247 3 47,B 988 5 71,B 3951
0 0,C 65 2 24,C 262 4 48,C 1047 6 72,C 4186
0 1,C# 69 2 25,C# 277 4 49,C# 1109 6 73,C#
0 2,D 73 2 26,D 294 4 50,D 1175 6 74,D
0 3,D# 78 2 27,D# 311 4 51,D# 1245 6 75,D#
0 4,E 41 2 28,E 330 4 52,E 1318 6 76,E
0 5,F 44 2 29,F 349 4 53,F 1397 6 77,F
0 6,F# 92 2 30,F# 370 4 54,F# 1480 6 78,F#
0 7,G 98 2 31,G 392 4 55,G 1568 6 79,G
0 8,G# 104 2 32,G# 415 4 56,G# 1661 6 80,G#
0 9,A 110 2 33,.A 440 4 57,A 1760 6 81,A
0 10,A# 117 2 34,A# 466 4 58,A# 1865 6 82,A#
0 11,B 123 2 35,B 494 4 59,B 1976 6 83,B
6 84,B#

Abaixo está a sintaxe das instruções SndOpen e SndPlay. Essas instruções

53
são exclusivas do QB64. A instrução SndOpen carrega o sinal de áudio de um
arquivo e o retorna para que seja armazenado em uma variável. A instrução
SndPlay toca o som armazenado na variável.
variable = _SndOpen ( filename )
_SndPlay variable

Abaixo está um exemplo de uso das instruções SndOpen e SndPlay tocando


quatro compassos de bateria.
hihat & = _SndOpen ( " ../ RNDrum / data / hihat03 . wav " )
kick & = _SndOpen ( " ../ RNDrum / data / kick03 . wav " )
snare & = _SndOpen ( " ../ RNDrum / data / snare03 . wav " )

IF hihat & <= 0 THEN ’ A leitura foi bem sucedida ?


PRINT " Error loading hihat . "
END IF
IF kick & <= 0 THEN ’ A leitura foi bem sucedida ?
PRINT " Error loading kick . "
END IF
IF snare & <= 0 THEN ’ A leitura foi bem sucedida ?
PRINT " Error loading snare . "
END IF

bpm = 120
beat = 60.0 / 120
Print " BPM = " ; bpm ; " beat = " ; beat * 1000; " ms "
For i = 1 To 4
_SndPlay kick &
_Delay beat / 2
_SndPlay hihat &
_Delay beat / 2
_SndPlay snare &
_Delay beat / 2
_SndPlay hihat &
_Delay beat / 2
Next i

Abaixo está a sintaxe da instruçao SndRaw. Essa instrução é exclusiva do


QB64. A instrução SndRaw toca um valor de amostra de uma forma de onda
entre -1 e 1 gerado por alguma função ou equação. Deve ser usada dentro de
um laço.
_SndRaw value

54
Abaixo está um exemplo de uso da instrução SndRaw. O código gera uma
onda senoidal multiplicada por um envelope exponencial que causa um decai-
mento na amplitude do sinal ao longo do tempo.
FREQ = 440 ’ frequencia de 36 a 10 ,000
Pi2 = 8 * Atn (1) ’2 * pi
Amplitude = .3 ’ 30% da amplitude maxima
SampleRate = _SndRate ’ define sample rate
FRate = FREQ / SampleRate ’ periodo em segundos
FPeriod = SampleRate / FREQ ’ amostras por periodo
Print " SndRate = " ; _SndRate
Print " FRate = " ; FRate
Print " FPeriod = " ; FPeriod

For Duration = 0 To 5 * SampleRate ’5 segundos


value = Amplitude * Sin ( Pi2 * Duration * FRate ) *
Exp ( - Duration / SampleRate ) ’ senoide
_SndRaw value
Next Duration
Do : Loop While _SndRawLen
End

5.2 Gráficos
Nesta seção descrevemos algumas instruções que podem ser usadas para gerar
saı́da gráfica no QBasic. A Tabela 5.4 lista as funções descritas nesta seção. As
funções iniciadas com sublinhado são exclusivas do QB64.

Tabela 5.4: Funções para saı́da gráfica

Operação Função
Ativa modo gráfico SCREEN
Define tamanho da fonte WIDTH
Desenha ponto na tela PSET
Desenha cı́rculo CIRCLE
Desenha linha ou retângulo LINE
Muda paleta de cores PALETTE

Quando o programa inicia, automaticamente é selecionado o modo de tela 0,


que não permite saı́da gráfica, somente de texto. Para que seja possı́vel desenhar
na tela, algum modo gráfico deve ser selecionado com a instrução SCREEN. Os
modos gráficos com melhor qualidade são 12 e 13. O modo 12 possui maior
resolução, porém menos cores. A Tabela 5.5 mostra os detalhes dos modos
gráficos. Opcionalmente é possı́vel alterar o tamanho da fonte com a instrução

55
WIDTH. A Tabela 5.5 mostra os valores possı́veis de colunas e linhas que podem
ser passados como parâmetro para WIDTH. Caso um número não permitido de
colunas ou linhas seja usado, uma mensagem de erro Illegal function call será
mostrada. O QB64 é mais flexı́vel e permite valores que o QuickBasic 4.5 não
permite. A instrução COLOR muda a cor do texto e do fundo. O modo gráfico 12
permite 16 cores e o modo 13 permite 256. Abaixo está a sintaxe das instruções
SCREEN, WIDTH e COLOR.
SCREEN mode
WIDTH [ columns ][ , lines ]
COLOR [ foreground ][ , background ]

Tabela 5.5: Modos de tela

Texto Gráfico Cores


Modo Colunas Linhas Largura Altura Simultâneas Total
0 80/40 25/43/50 Sem gráficos 16 16
12 80 30/60 640 480 16 218
13 40 25 320 200 256 218

Figura 5.1: Cores do modo gráfico 12.

56
O código abaixo pode ser usado para visualizar as cores do modo gráfico 12.
A Figura 5.1 mostra a saı́da resultante.
Screen 12
For i = 0 To 15
Locate i + 1 , 1
c = i
If i <= 1 Then
Color 15 , c
Else
Color 0 , c
End If
Print Using " ## " ; Spc (39) , c , Spc (39) ;
Next

O código abaixo pode ser usado para visualizar as cores do modo gráfico 13.
A Figura 5.2 mostra a saı́da resultante.
Screen 13
For j = 0 To 15
For i = 0 To 15
Locate ( i + 1) , (2 * j + 1)
c = i * 16 + j
If c <= 1 Or c >= 104 Or ( c >= 16 And c <= 23)
Then
Color 15 , c
Else
Color 0 , c
End If
If c < 16 Then
Print " 0 " ;
End If
Print Hex$ ( c )
Next
Next

As instruções PSET e CIRCLE desenham um ponto e um cı́rculo respectiva-


mente. A instrução LINE pode ser usada para desenhar um segmento de reta,
um retângulo vazio ou um retângulo preenchido a depender dos parâmetros re-
cebidos. Abaixo está a sintaxe dessas instruções. Os valores de x e y indicam as
coordenadas e o valor de color indica a cor. Quando o keyword STEP é usado,
as coordenadas são relativas à última coordenada usada. Na instrução CIRCLE,
os parâmetros startRadian e stopRadian são valores entre 0 e 2π que podem
ser usados para desenhar uma fatia de um cı́rculo; o parâmetro aspect é um
valor positivo que indica a razão entre a altura e a largura do cı́rculo, e, quando

57
Figura 5.2: Cores do modo gráfico 13.

diferente de 1 representa uma elipse. Na instrução LINE, as coordenadas entre


parênteses indicam o ponto inicial e final do segmento de reta. Quando B é
usado, um retângulo vazio é desenhado com cantos nas coordenadas indicadas;
quando BF é usado, um retângulo preenchido é desenhado; o parâmetro style é
um inteiro cujos 16 bits menos significativos são interpretados como um padrão
de pontilhado para o contorno do retângulo.
PSET [ STEP ] (x , y ) [ , color ]
CIRCLE [ STEP ]( x , y ) , radius , [ color ][ , startRadian ,
stopRadian ] [ , aspect ]
LINE [ STEP ] [( x1 , y1 ) ] -[ STEP ] ( x2 , y2 ) , color [ ,
[{ B | BF }] , style ]

A instrução PALETTE pode ser usada para modificar as cores nos modos
gráficos. O parâmetro color é um inteiro de 0 a 15 no modo 12 ou um inteiro
de 0 a 255 no modo 13. Os parâmetros red, green e blue são inteiros de 0 a
63. Quando os três valores são iguais, a cor obtida é um tom de cinza.
PALETTE [ color , red + ( green * 2^8) + ( blue * 2^16) ]

58
Abaixo está um exemplo de uso de PALETTE e COLOR. O código abaixo pre-
enche a tela com caracteres em posições e cores aleatórias.
Screen 12
nRow = 30 ’ 30 or 60
Width 80 , nRow

For n = 1 To 15
Palette n , 0 + (4 * n * 256) + (0 * 65536)
Next n

For n = 1 To 10001
i = Int ( Rnd * ( nRow - 1) ) + 1
j = Int ( Rnd * 80) + 1
f = Int ( Rnd * 16)
b = Int ( Rnd * 16)
c = Int ( Rnd * 93) + 33
Locate i , j
Color f , b
Print Chr$ ( c ) ;
_Delay 0.001
Next n

Abaixo está um exemplo de uso de PALETTE e LINE. O código abaixo preenche


a tela com segmentos de reta. Para desenhar retângulos, adicione B ou BF à
instrução LINE.
Screen 12

For n = 1 To 15
Palette n , (4 * n ) + (4 * n * 256) + ((63 - 4 * n )
* 65536)
Next n

w = 640
h = 480
For n = 1 To 10001
x0 = Int ( Rnd * w )
y0 = Int ( Rnd * h )
x1 = Int ( Rnd * w )
y1 = Int ( Rnd * h )
f = Int ( Rnd * 16)
Line ( x0 , y0 ) -( x1 , y1 ) , f ’[ ,{ B | BF }]
_Delay 0.001
Next n

59
O código abaixo desenha faixas coloridas na tela. O modo gráfico é o 13,
que possui 256 cores. As 16 primeiras são as mesmas do modo gráfico 12. A
seguir temos 16 escalas de cinza e 24 cores do arco-ı́ris saturadas, ou seja, sem
mistura com branco ou preto. As demais são variações não saturadas das cores
do arco-ı́ris. A variável c é usada para armazenar a cor, que irá variar de 16
a 55. A instrução LINE desenha faixas no canto superior esquerdo da tela. A
instrução CIRCLE desenha os arcos no canto inferior direito. Observe que a
instrução CIRCLE está repetida com um raio 0.5 pixels maior que na instrução
anterior para evitar falhas, que aparecem como pixels pretos, no preenchimento
dos arcos.
Screen 13

For i = 0 To 39
c = i + 16
Line (0 , 100 + i ) -(100 + i , 0) , c
Circle (320 , 200) , 100 + i , c
Circle (320 , 200) , 100.5 + i , c
Next i

5.2.1 Tiles and sprites


Tiles são pequenas figuras úteis para desenhar padrões repetitivos, com propri-
edades como possibilidade ou não e andar sobre elas etc. Sprites são pequenas
figuras que podem, ao contrário dos tiles, se mover pela tela. Ambos são peque-
nos bitmaps usados para desenhar gráficos bidimensionais e a partir daqui não
faremos distinção entre eles. Podem ser implementadas com as instruções GET e
PUT. Depois de desenhar algum padrão na tela, a instrução GET pode ser usada
para salvar esse padrão em um vetor de inteiros. Em seguida, a instrução PUT
pode ser usada para desenhar esse padrão nas coordenadas desejadas da tela.
Vários sprites podem ser armazenados em um mesmo vetor desde que separados
por ı́ndices suficientes, no mı́nimo 2 + h × w/2 onde w é a largura do sprite em
pixels e h é a altura. Abaixo está a sintaxe das instruções GET e PUT.
GET ( x1 , y1 ) -( x2 , y2 ) , array ( index )
PUT (x , y ) , array ( index ) , PSET

A Figura 5.3 mostra exemplos de sprites que podem ser usadas lado a lado
para preencher uma cena1 . A Figura 5.4 mostra exemplos de jogos bidimensio-
nais para PC. A Figura 5.5 mostra outros exemplos de jogos bidimensionais.

1 [Link]

60
Figura 5.3: Exemplos de pixel art. Fonte: Shutterstock.

(a) Prince of Persia (1989) (b) SimCity (1989)

Figura 5.4: Exemplos de jogos bidimensionais para PC.

(a) Super Mario Bros. (1985) (b) Galaga (1981)

Figura 5.5: Outros exemplos de jogos bidimensionais.

61
O código abaixo desenha quatro sprites diferentes com 16×16 pixels, os salva
em um vetor e os desenha na tela repetidamente.

Screen 13
scW = 320 ’ Screen width
scH = 200 ’ Screen height
W = 16 ’ Sprite width
H = 16 ’ Sprite height
spOffset = W * H / 2 + 2
spN = 4
Dim arrSprite ( spN * spOffset ) As Integer

’ Sprite 0: gray tile


spGray = 0
Line (0 , 0) -(15 , 15) , 15 , BF
Line (1 , 1) -(15 , 15) , 8 , BF
Line (1 , 1) -(14 , 14) , 7 , BF
Get (0 , 0) -(15 , 15) , arrSprite ( spGray * spOffset )
’ Sprite 1: chess tile
spChess = 1
Cls
Line (0 , 0) -( W / 2 - 1 , H / 2 - 1) , 15 , BF
Line ( W / 2 , H / 2) -(W , H ) , 15 , BF
Get (0 , 0) -( W - 1 , H - 1) , arrSprite ( spChess *
spOffset )
’ Sprite 2: brick tile
spBrick = 2
Cls
Line (0 , 0) -( W - 1 , H - 1) , 12 , BF
Line (0 , 0) -(0 , H / 2 - 1) , 4 ’ Vertical
Line ( W / 2 , H / 2) -( W / 2 , H - 1) , 4 ’ Vertical
Line (0 , H / 2) -( W - 1 , H / 2) , 4 ’ Horizontal
Line (0 , 0) -( W - 1 , 0) , 4 ’ Horizontal
Get (0 , 0) -( W - 1 , H - 1) , arrSprite ( spBrick *
spOffset )
’ Sprite 3: smiley
spSmile = 3
Cls
Circle (( W - 1) / 2 , ( H - 1) / 2) , ( W / 2) , 14
Paint (( W - 1) / 2 , ( H - 1) / 2) , 14
Circle (( W - 1) / 2 , ( H - 1) / 2) , ( W / 3) , 0 , (210 *
3.14 / 180) , (330 * 3.14 / 180) ’ Mouth
PSet ( W / 3 , H / 3) , 0 ’ Left eye
PSet (2 * W / 3 , H / 3) , 0 ’ Right eye
Get (0 , 0) -( W - 1 , H - 1) , arrSprite ( spSmile *
spOffset )

62
For x = 0 To Int ( scW / W ) - 1
For y = 0 To Int ( scH / H ) - 1
spId = Int ( spN * y / ( scH / H - 1) )
Put ( x * W , y * H ) , arrSprite ( spId * spOffset ) ,
PSet
Next y
Next x

A Figura 5.6 mostra um exemplo de saı́da do código acima.

Figura 5.6: Tela de saı́da com sprites definidas com figuras geométricas, como
segmentos de reta, retângulos, cı́rculos e arcos de cı́rculo.

Ao invés de desenhar os sprites com segmentos de reta arcos de cı́rculo,


é possı́vel definir bitmaps, ou seja, os valores dos pixels individualmente. A
instrução DATA define os valores dos pixels individuais e READ pode ser colocado
dentro de laços para os ler um a um. Um número de READ maior que o número
de DATA disponı́vel causa um erro.
O código abaixo define um sprite com 20×20 pixels. As variáveis no inı́cio
do código armazenam a largura e altura da tela, largura e altura do sprite e o
tamanho do vetor de inteiros necessário para armazenar o sprite.
Screen 13
scW = 320 ’ Screen width
scH = 200 ’ Screen height
spW = 20 ’ Sprite width
spH = 20 ’ Sprite height
Dim spOffset As Integer
spOffset = spW * spH / 2 + 2 ’ Array p o s i t i o n s n e c e s s a r y

63
Data 01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01
Data 01 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02
Data 01 ,02 ,06 ,03 ,06 ,06 ,05 ,06 ,06 ,06 ,07 ,06 ,06 ,06 ,05 ,06 ,06 ,03 ,06 ,02
Data 01 ,02 ,03 ,03 ,03 ,04 ,06 ,06 ,06 ,07 ,08 ,07 ,06 ,06 ,06 ,04 ,03 ,03 ,03 ,02
Data 01 ,02 ,06 ,03 ,04 ,04 ,06 ,06 ,07 ,08 ,09 ,08 ,07 ,06 ,06 ,04 ,04 ,03 ,06 ,02
Data 01 ,02 ,06 ,04 ,04 ,04 ,06 ,07 ,08 ,09 ,10 ,09 ,08 ,07 ,06 ,04 ,04 ,04 ,06 ,02
Data 01 ,02 ,06 ,06 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,06 ,05 ,02
Data 01 ,02 ,06 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,06 ,02
Data 01 ,02 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,13 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,02
Data 01 ,02 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,13 ,14 ,13 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,02
Data 01 ,02 ,07 ,08 ,09 ,10 ,11 ,12 ,13 ,14 ,15 ,14 ,13 ,12 ,11 ,10 ,09 ,08 ,07 ,02
Data 01 ,02 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,13 ,14 ,13 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,02
Data 01 ,02 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,13 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,02
Data 01 ,02 ,06 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,12 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,06 ,02
Data 01 ,02 ,06 ,06 ,06 ,06 ,07 ,08 ,09 ,10 ,11 ,10 ,09 ,08 ,07 ,06 ,06 ,06 ,05 ,02
Data 01 ,02 ,06 ,04 ,04 ,04 ,06 ,07 ,08 ,09 ,10 ,09 ,08 ,07 ,06 ,04 ,04 ,04 ,06 ,02
Data 01 ,02 ,06 ,03 ,04 ,04 ,06 ,06 ,07 ,08 ,09 ,08 ,07 ,06 ,06 ,04 ,04 ,03 ,06 ,02
Data 01 ,02 ,03 ,03 ,03 ,04 ,06 ,06 ,06 ,07 ,08 ,07 ,06 ,06 ,06 ,04 ,03 ,03 ,03 ,02
Data 01 ,02 ,06 ,03 ,06 ,06 ,05 ,06 ,06 ,06 ,07 ,06 ,06 ,06 ,05 ,06 ,06 ,03 ,06 ,02
Data 01 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02

Abaixo está a declaração do vetor que armazena o sprite e a chamada à


função que faz a leitura dos dados e salvamento no array arrSprite.
Dim arrSprite ( spOffset ) As Integer
Call spRead ( arrSprite () , spW , spH )

Os laços abaixo preenchem a tela com tantas cópias do sprite quanto ne-
cessário.
For X = 0 To scW \ spW - 1
For Y = 0 To scH \ spH - 1
Call spDraw ( arrSprite () , X * spW , Y * spH )
Next Y
Next X

O laço abaixo sorteia valores aleatórios de cores e modifica a paleta enquanto


o usuário não pressionar a tecla [Esc].
Do
For i = 1 To 15
r = Int ( Rnd * 64)
g = Int ( Rnd * 64)
b = Int ( Rnd * 64)
Palette i , r + ( g * 256) + ( b * 65536)
Next i
_Delay 0.2
Loop While InKey$ <> Chr$ (27)

64
A função abaixo faz a leitura dos pixels do sprite armazenados nas instruções
DATA e os transfere para o vetor arrSprite.
Sub spRead ( arrSprite () As Integer , spW , spH )
For Y = 0 To spH - 1 ’ For each row
For X = 0 To spW - 1 ’ For each column
Read DotColor
PSet (X , Y ) , DotColor
Next X
Next Y
Get (0 , 0) -( spW - 1 , spH - 1) , arrSprite (0)
End Sub

A função abaixo desenha uma única instância do sprite armazenado em


arrSprite com canto superior direito posicionado nas coordenadas X eY. Para
preencher a tela, deve ser chamada várias vezes em um laço.
Sub spDraw ( arrSprite () As Integer , X , Y )
Put (X , Y ) , arrSprite (0) , PSet
End Sub

A Figura 5.7 mostra um exemplo de saı́da do código acima.

Figura 5.7: Tela de saı́da com sprites definidas com DATA e sorteio de cores.

65
Abaixo são definidos 13 sprites com Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
16×16 pixels cada. A variável nSprite Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
armazena o número de sprites, a vari- Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10
vel spW armazena a largura em pixels Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,10 ,10 ,10 ,10 ,10
de cada sprite, spH armazena a altura e Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,10
spOffset armazena o espaço necessário Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10
em um array de inteiros para armaze- spBuTM = 6
Data 09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,00 ,00 ,09 ,09 ,09 ,09 ,09 ,09
nar cada sprite. Data 09 ,09 ,09 ,09 ,09 ,00 ,10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,00 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09
Screen 13 Data 09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,00 ,09 ,00 ,09 ,09
Data 09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,00 ,10 ,00 ,09
spSky = 1 Data 09 ,09 ,00 ,10 ,10 ,10 ,10 ,10 ,10 ,02 ,10 ,10 ,10 ,10 ,10 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,00 ,10 ,10 ,10 ,02 ,02 ,10 ,10 ,10 ,02 ,10 ,10 ,10 ,10 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,10 ,10 ,10 ,02 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 spBuTR = 7
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
spFloor = 2 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00 ,06 ,12 ,12 ,12 ,12 ,06 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 00 ,09 ,09 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 00 ,09 ,00 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,00 ,00 ,00 ,00 ,06 Data 10 ,00 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,12 ,12 ,12 ,12 ,00 Data 10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 10 ,10 ,10 ,10 ,10 ,00 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 10 ,10 ,10 ,10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,00 Data 10 ,10 ,10 ,10 ,10 ,10 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 00 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,06 ,00 spClTL = 8
Data 12 ,12 ,00 ,00 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,06 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,12 ,12 ,00 ,00 ,00 ,00 ,12 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,12 ,12 ,12 ,00 ,12 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 12 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,12 ,06 ,06 ,06 ,06 ,06 ,00 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,00 ,00 ,00 ,00 ,00 ,00 ,06 ,12 ,00 ,00 ,00 ,00 ,00 ,00 ,06 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
spQuest = 3 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,12 ,00 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,00
Data 06 ,12 ,12 ,12 ,12 ,06 ,06 ,06 ,06 ,06 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,06 ,06 ,00 ,00 ,00 ,06 ,06 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,15 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,15 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,12 ,00 ,00 ,12 ,06 ,06 ,06 ,00 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,06 ,06 ,00 ,00 ,00 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00 ,00 ,12 ,12 ,12 ,12 ,12 ,00 spClTM = 9
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,06 ,06 ,12 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,00 ,00 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,06 ,06 ,00 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09
Data 06 ,12 ,00 ,12 ,12 ,12 ,12 ,12 ,00 ,00 ,12 ,12 ,12 ,00 ,12 ,00 Data 09 ,09 ,09 ,00 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09
Data 06 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00 Data 09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,00 ,09 ,09
Data 00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 Data 09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,15 ,00 ,09
spBrick = 4 Data 09 ,09 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,09 ,15 ,15 ,15 ,15 ,15 ,00
Data 12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 Data 09 ,00 ,15 ,15 ,15 ,09 ,09 ,15 ,15 ,15 ,09 ,15 ,15 ,15 ,15 ,00
Data 06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 00 ,15 ,15 ,15 ,09 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,00
Data 06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15
Data 06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 spClTR = 10
Data 00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 ,06 ,06 ,06 ,00 ,06 ,06 ,06 ,06 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 ,00 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
spBuTL = 5 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,09 ,09 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,09 ,00 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09

66
Data 15 ,00 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,06 ,14 ,06 ,06 ,14 ,14 ,14 ,06 ,14 ,14 ,14
Data 15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,06 ,06 ,14 ,14 ,14 ,14 ,06 ,06 ,06 ,06 ,00
Data 15 ,15 ,15 ,15 ,15 ,00 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,00 ,00 ,14 ,14 ,14 ,14 ,14 ,14 ,14 ,00 ,00
Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,00 ,06 ,06 ,12 ,06 ,06 ,06 ,00 ,00 ,00 ,00
Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 00 ,06 ,06 ,06 ,12 ,06 ,06 ,12 ,06 ,06 ,06 ,00
Data 15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 06 ,06 ,06 ,06 ,12 ,12 ,12 ,12 ,06 ,06 ,06 ,06
spClBL = 11 Data 14 ,14 ,06 ,12 ,14 ,12 ,12 ,14 ,12 ,06 ,14 ,14
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,09 ,15 ,15 Data 14 ,14 ,14 ,12 ,12 ,12 ,12 ,12 ,12 ,14 ,14 ,14
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,09 ,15 Data 14 ,14 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,14 ,14
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,09 Data 00 ,00 ,12 ,12 ,12 ,00 ,00 ,12 ,12 ,12 ,00 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,15 ,15 ,15 Data 00 ,06 ,06 ,06 ,00 ,00 ,00 ,00 ,06 ,06 ,06 ,00
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,00 ,00 ,00 Data 06 ,06 ,06 ,06 ,00 ,00 ,00 ,00 ,06 ,06 ,06 ,06
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 marioW = 12
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 marioH = 16
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Abaixo está o mapa do cenário. O
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 valor de cada posição representa um
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
spClBM = 12 sprite. O valor 01 corresponde a spSky,
Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,09 ,15 ,15 ,15 ,15 ,15 ,15
Data 15 ,09 ,15 ,15 ,15 ,15 ,15 ,15 ,09 ,15 ,15 ,15 ,15 ,15 ,15 ,15 o valor 02 corresponde a spFloor e as-
Data 09 ,09 ,09 ,15 ,15 ,15 ,09 ,09 ,09 ,09 ,15 ,15 ,15 ,15 ,09 ,15
Data 15 ,15 ,09 ,09 ,09 ,09 ,09 ,09 ,15 ,09 ,09 ,09 ,09 ,09 ,15 ,15 sim por diante. A variável mapW arma-
Data 15 ,15 ,15 ,15 ,09 ,09 ,15 ,15 ,15 ,15 ,09 ,09 ,09 ,15 ,15 ,15
Data 00 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,15 ,15 ,15 ,15 ,15 ,15 ,15 ,15 zena a largura do cenário e mapH arma-
Data 09 ,00 ,00 ,15 ,15 ,15 ,00 ,09 ,00 ,00 ,15 ,15 ,15 ,15 ,00 ,00
Data 09 ,09 ,09 ,00 ,00 ,00 ,09 ,09 ,09 ,09 ,00 ,00 ,00 ,00 ,09 ,09 zena sua altura.
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,01 ,08 ,09 ,10 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,01 ,11 ,12 ,13 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,08 ,09 ,10 ,01 ,01 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,11 ,12 ,13 ,01 ,01 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,03 ,04 ,03 ,04 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,05 ,06 ,06 ,06 ,07 ,01 ,01
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 Data 02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02
spClBR = 13 Data 02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02 ,02
Data 15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 mapW = 16
Data 15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 mapH = 8
Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 15 ,15 ,15 ,15 ,15 ,15 ,15 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 15 ,15 ,15 ,15 ,15 ,00 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 00 ,15 ,15 ,00 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,00 ,00 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
Data 09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09 ,09
nSprites = spClBR
spW = 16
spH = 16
Dim spOffset As Integer
spOffset = spW * spH / 2 + 4

Os dados abaixo armazenam o sprite


do personagem. A variável marioW ar-
mazena sua largura em pixels e marioH
armazena sua altura. Neste sprite, in-
terpretaremos os pixels com valor 00
como se fossem transparentes, ou seja,
não serão desenhados para que o cenário
apareça no lugar deles. Este compor-
tamento será implementado na função
marioDraw.
Data 00 ,00 ,00 ,12 ,12 ,12 ,12 ,12 ,00 ,00 ,00 ,00
Data 00 ,00 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,12 ,00
Data 00 ,00 ,06 ,06 ,06 ,14 ,14 ,06 ,14 ,00 ,00 ,00
Data 00 ,06 ,14 ,06 ,14 ,14 ,14 ,06 ,14 ,14 ,14 ,00

67
Abaixo estão as declarações dos vetores que armazenarão os dados acima.
O vetor arrSprite armazenará os 13 sprites, marioSprite armazenará os per-
sonagem e matMap armazenará o mapa do cenário.
Dim arrSprite (0 To nSprites * spOffset ) As Integer
Dim marioSprite ( spOffset ) As Integer
Dim matMap (0 To mapW - 1 , 0 To mapH - 1) As Integer

O laço abaixo faz a leitura de cada sprite e os desenha na parte inferior da


tela.
For s = 1 To nSprites
Call spRead (s , spOffset , arrSprite () , spW , spH )
Call spDraw (s , spOffset , arrSprite () , ( s - 1) *
spW , 160)
Sleep
Next s

A chamada abaixo faz a leitura do sprite do personagem e o desenha também


na parte inferior da tela.
Call spRead (1 , spOffset , marioSprite () , marioW ,
marioH )
Call marioDraw (1 , spOffset , marioSprite () , ( nSprites
- 1) * spW , 160)

Abaixo é feita a leitura do mapa e em seguida o cenário é desenhado. Final-


mente, o personagem é desenhado sobre o cenário.
Call mapRead ( matMap () , mapW , mapH )
Call mapDraw ( matMap () , mapW , mapH , spOffset ,
arrSprite () , spW , spH )
Call marioDraw (1 , spOffset , marioSprite () , 11 * spW ,
5 * spH )

Aqui termina o código do programa principal. Abaixo são definidas as


funções usadas.

68
A função abaixo calcula o ı́ndice da primeira posição de cada sprite no array.
A função recebe um id maior que zero e spOffset é o número de posições
necessárias no array para armazenar cada sprite.
Function getSpriteIdx ( id , spOffset )
If id <= 0 Then
Print " getSpriteIdx : Error : id <= 0 "
End If
getSpriteIdx = ( id - 1) * spOffset
End Function

A função abaixo faz a leitura de um sprite individual. A função recebe


cinco parâmetros. O primeiro é o id do sprite. O segundo é o valor de spOffset
precalculado, que indica o espaço necessário para armazenar um sprite no array.
O terceiro é o array que armazena os sprites. Os dois últimos são a largura e
altura em pixels de cada sprite respectivamente. É usada também para ler o
sprite do personagem.
Sub spRead ( id , spOffset , arrSprite () As Integer ,
spW , spH )
For Y = 0 To spH - 1 ’ For each row
For X = 0 To spW - 1 ’ For each column
Read DotColor
PSet (X , Y ) , DotColor
Next X
Next Y
idx = getSpriteIdx ( id , spOffset )
Locate 20 , 1
Print id ; idx
Get (0 , 0) -( spW - 1 , spH - 1) , arrSprite ( idx )
End Sub

A função abaixo desenha um sprite na tela. A função recebe cinco parâmetros.


O primeiro é o id do sprite. O segundo é o valor de spOffset. O terceiro é o
array que armazena os sprites. Os dois últimos são as coordenadas na tela onde
o pixel superior esquerdo do sprite deve ficar.
Sub spDraw ( id , spOffset , arrSprite () As Integer , X ,
Y)
Put (X , Y ) , arrSprite ( getSpriteIdx ( id , spOffset ) ) ,
PSet
End Sub

69
A função abaixo desenha o personagem na tela. Recebe os mesmos parâmetros
que spDraw. Seu comportamento, porém, é diferente pois considera que os pixels
com valor 00 são transparentes.
Sub marioDraw ( id , spOffset , arrSprite () As Integer ,
X, Y)
bytes = arrSprite (0)
spH = arrSprite (1)
spW = 2 * bytes \ arrSprite (1)
nPix = spH * spW
For p = 0 To nPix - 1
pX = p Mod spW
pY = p \ spW
b = p \ 2
v = arrSprite ( b + 2)
If p Mod 2 = 0 Then
c = v Mod 256
Else
c = v \ 256
End If
If c <> 0 Then
PSet ( X + pX , Y + pY ) , c
End If
Rem Sleep
Next p
End Sub

A função abaixo faz a leitura do mapa. A função recebe três parâmetros. O


primeiro é o array que armazena o mapa. Os dois últimos são a largura e altura
do mapa em número de sprites respectivamente.
Sub mapRead ( matMap () As Integer , mapW , mapH )
For Y = 0 To mapH - 1 ’ For each row
For X = 0 To mapW - 1 ’ For each column
Read spId
matMap (X , Y ) = spId
Next X
Next Y
End Sub

A função abaixo desenha o cenário. A função recebe sete parâmetros. O


array que armazena o mapa, largura e altura do mapa em número de sprites, o
valor de spOffset, o array que armazena os sprites, largura e altura em pixels
de cada sprite.

70
Sub mapDraw ( matMap () As Integer , mapW , mapH ,
spOffset , arrSprite () As Integer , spW , spH )
For Y = 0 To mapH - 1 ’ For each row
For X = 0 To mapW - 1 ’ For each column
spId = matMap (X , Y )
scX = X * spW + 32
scY = Y * spH + 0
Call spDraw ( spId , spOffset , arrSprite () , scX ,
scY )
Next X
Next Y
End Sub

A Figura 5.8 mostra a saı́da do código acima.

Figura 5.8: Tela de saı́da com o cenário definido com sprites.

5.3 Exercı́cios
1. Crie um programa que toque arpejos musicais. Use a instrução PLAY com
strings contendo notas musicais definidas por números como em "N24 N28
N31 N36". Toque arpejos

(a) maiores, com intervalos de 4, 7 e 12 semitons.


(b) maiores, subindo e depois descendo.

71
(c) menores, com intervalos de 4, 6 e 12 semitons.
(d) menores, subindo e depois descendo.
(e) maiores com sétima, com intervalos de 4, 7 e 11 semitons.
(f) maiores com sétima, subindo e depois descendo.
(g) maiores com sétima menor, com intervalos de 4, 7 e 10 semitons.
(h) maiores com sétima menor, subindo e depois descendo.
2. Crie um programa para visualizar gráficos de funções. Procure desenhar
linhas contı́nuas, de modo que os pontos da função não apareçam isolados.
Desenhe uma função

(a) identidade.
(b) afim.
(c) polinomial de segundo grau.
(d) polinomial de terceiro grau.
(e) exponencial.
(f) logarı́tmica.
(g) senoidal.
(h) 200 exp(−x2 ).
3. Crie um programa para vizualizar funções tridimensionais. Escolha cores
diferentes para diferentes faixas de valores de z. Considere que os eixos x
e y correspondem aos eixos horizontal e vertical respectivamente. Desenhe
a função
(a) paraboloide hiperbólica z = xy.
(b) paraboloide cilı́ndrica z = x2 .
(c) paraboloide cilı́ndrica z = y 2 .
(d) paraboloide de revolução z = x2 + y 2 .
(e) paraboloide elı́ptica z = a−2 x2 + b−2 y 2 .
(f) paraboloide hiperbólica z = a−2 x2 − b−2 y 2 .

4. Refaça a questão anterior escolhendo cores diferentes em função da deri-


vada parcial de z em relação a y. Encontre a derivada parcial numerica-
mente usando a fórmula ∂y ∂
f (x, y) = f (x,y+ε)−f
ε
(x,y)
.

72
Capı́tulo 6

Jogos baseados em texto

Os primeiros jogos baseados em texto, populares nas décadas de 1960 e 1970,


serviram de inspiração para os gêneros de aventura e role-playing games (RPG).
Alguns exemplos notáveis são Oregon Trail1 e Star Trek2 . É possı́vel jogar vários
desses jogos online3 .
Neste capı́tulo veremos um exemplo simples de implementação de um RPG
baseado em texto.

6.1 Um RPG simples


O jogo UFS Simulator: A Text Based RPG simula um mês de um aluno da
UFS. O aluno tem 30 dias para estudar e ser aprovado em duas disciplinas. É
necessário maximizar o nı́vel de conhecimento e ao mesmo tempo minimizar o
stress e cansaço, pois ambos diminuem o rendimento. Caso o nı́vel de stress
ou cansaço chegue a 100%, o aluno surta e não consegue mais estudar para as
provas.
O jogo começa com a apresentação de um texto introdutório.

1 [Link]
2 [Link]
3 [Link]

73
Print ""
Print " Seja bem vindo a UFS ! Voce eh calouro no curso "
Print " de Engenharia e esta super empolgado com a "
Print " aprovacao . Seus pais estao muito orgulhosos . "
Print " Vamos ver como voce se sai ... "
Print ""
Print " A primeira prova sera em 30 dias . Tente "
Print " equilibrar estudos , diversao e descanso para "
Print " maximizar sua produtividade e nao surtar . "
Print ""

O jogo armazena o status em uma estrutura com quatro variáveis que arma-
zenam o percentual de conhecimento nas disciplinas de Cálculo, Computação,
percentual de stress e de cansaço. Todas começam com zero e podem chegar
até 100.
Type TStatus
estcalc As Integer
estcomp As Integer
stress As Integer
cansaco As Integer
End Type

Dim Status As TStatus

Status . estcalc = 0
Status . estcomp = 0
Status . stress = 0
Status . stress = 0

O laço principal do jogo conta quantos dias faltam para as provas. Começa
fantando 30 dias. Quando o contador chega em zero, ou seja, no dia da prova,
a nota é sorteada. Quando maior o percentual de conhecimento, maior a nota.
A cada iteração do laço é mostrado o número de dias que faltam para a prova,
o valor das variáveis de status e um menu de ações. Quatro ações são possı́veis:
estudar Cálculo, estudar Computação, sair para beber e descansar. Cada dia
permite uma única ação. O efeito de uma ação de estudar é incrementar o per-
centual de conhecimento na disciplina correspondente, mas também aumenta o
percentual de stress e cansaço em 5 pontos percentuais. O aumento de conheci-
mento é maior quanto menor o percentual de stress e cansaço. O efeito de sair
para beber é diminuir em 20 pontos percentuais o stress e aumentar o cansaço
em 5. O efeito de descansar é diminuir o stress em 5 pontos percentuais e o de
cansaço em 10.
Caso o nı́vel de stress ou cansaço chegue a 100%, o aluno surta e não consegue
mais estudar até o dia da prova.

74
For d = 30 To 1 Step -1
Print " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
Print " Faltam " ; d ; " dias para as provas . "
Print " "
Print " Conhecimento de calculo = ";
Status . estcalc ; " % "
Print " Conhecimento de computacao = " ;
Status . estcomp ; " % "
Print " Nivel de stress = ";
Status . stress ; " % "
Print " Nivel de cansaco = ";
Status . cansaco ; " % "
Print " "
Print " 1 - Estudar calculo "
Print " 2 - Estudar computacao "
Print " 3 - Sair para beber "
Print " 4 - Descansar "
Print " "
Input " O que voce vai fazer hoje ? " , escolha
p = Int (5 - 5 * ( Status . stress / 100) *
( Status . cansaco / 100) )
Select Case escolha
Case 1
Status . estcalc = mudaStatus ( Status . estcalc , p )
Status . stress = mudaStatus ( Status . stress , 5)
Status . cansaco = mudaStatus ( Status . cansaco , 5)
Case 2
Status . estcomp = mudaStatus ( Status . estcomp , p )
Status . stress = mudaStatus ( Status . stress , 5)
Status . cansaco = mudaStatus ( Status . cansaco , 5)
Case 3
Status . stress = mudaStatus ( Status . stress , -20)
Status . cansaco = mudaStatus ( Status . cansaco , 5)
Case 4
Status . stress = mudaStatus ( Status . stress , -5)
Status . cansaco = mudaStatus ( Status . cansaco , -10)
End Select
If Status . stress > 50 Then
Print " Seu nivel de stress esta alto . Tente
descansar ou sair um pouco para nao surtar . "
End If
If Status . stress >= 100 Then
Print " Seu nivel de stress chegou no limite . "
Print " Voce decidiu largar a engenharia para ir
vender coco na praia . "
Exit For

75
End If
If Status . cansaco > 50 Then
Print " Seu nivel de cansaco esta alto . Tente
descansar um pouco para ser mais produtivo . "
End If
If Status . cansaco >= 100 Then
Print " Seu nivel de cansaco chegou no limite . "
Print " Voce decidiu largar a engenharia para
trabalhar de ajudante de pedreiro . "
Exit For
End If
Next d

No dia das provas, as notas são sorteadas, exibidas e é mostrada uma men-
sagem avisando se o aluno foi aprovado ou reprovado em cada disciplina.
Print " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
Print " Chegou o dia da prova de calculo "
NCalculo = sorteiaNota ( Status . estcalc )
Print " Sua nota de calculo foi " ; NCalculo
Print msgNota ( NCalculo )

Print " Chegou o dia da prova de computacao "


NComp = sorteiaNota ( Status . estcomp )
Print " Sua nota de computacao foi " ; NComp
Print msgNota ( NComp )

A função sorteiaNota soma ao percentual de estudo um valor aleatório


entre -25 e +25. Em seguida divide o valor por 10. A nota precisa ficar entre 0
e 10.
Function sorteiaNota ( estudo )
nota = Int ( estudo + ( Rnd * 50 - 25) ) / 10
If nota < 0 Then
nota = 0
ElseIf nota > 10 Then
nota = 10
End If
sorteiaNota = nota
End Function

A função msgNota retorna uma mensagem em função da nota. Caso a nota


seja menor que 5, o aluno é reprovado. Caso contrário, o aluno é aprovado.

76
Function msgNota$ ( nota )
If nota < 5 Then
msgNota$ = " Lamentavel ... voce se lascou "
Else
msgNota$ = " Muito bem ! voce foi aprovado ! "
End If
End Function

A função mudaStatus soma ao valor do status a variação correspondente à


ação e retorna o resultado. A função se certifica de que o status permaneça no
intervalo de 0 a 100.

Function mudaStatus ( status , delta )


status = status + delta
If status < 0 Then
status = 0
ElseIf status > 100 Then
status = 100
End If
mudaStatus = status
End Function

Figura 6.1: Tela inicial do Corrida Aritmetica.

77
6.2 Animação e ASCII art
O jogo Corrida Aritmética demonstra como fazer uma animação simples com
ASCII art. O objetivo é responder perguntas sobre aritmética. O jogador com
mais acertos vence.
O código abaixo inicializa as variáveis do programa. As variáveis SHARED
são visı́veis dentro do escopo das funções. A variável arr é um array armazena
o status dos dois jogadores, ou seja, pontuação, coordenadas do carro e cor.
Dim Shared car0$
Dim Shared car1$
Dim Shared car2$
car0$ = " _ _ "
car1$ = " \ ‘../ | o_ .. __ "
car2$ = " ‘. ,( _ ) ______ ( _ ) . > "

Dim Shared colorTrack


colorTrack = 7
maxCol = 60

Type TPlayer
lineP As Integer
columnP As Integer
colorP As Integer
scoreP As Integer
End Type
Dim Shared arr (2) As TPlayer

arr (1) . lineP = 2


arr (2) . lineP = 6
arr (1) . columnP = 1
arr (2) . columnP = 1
arr (1) . colorP = 9
arr (2) . colorP = 4
arr (1) . scoreP = 0
arr (2) . scoreP = 0

O código abaixo inicia o jogo com a exibição do tı́tulo, uma pequena animação
dos carros percorrendo a tela e mostra uma bandeira quadriculada na parte in-
ferior da tela. O jogador é consultado quanto ao número de rodadas do jogo. A
Figura 6.1 mostra a tela inicial do jogo.
Locate 10 , 32
Color 0 , 7
Print " Corrida aritmetica "
Call printTrack

78
For col = 1 To 60
Call printCar ( arr (1) . lineP , col , arr (1) . colorP )
Call printCar ( arr (2) . lineP , col , arr (2) . colorP )
_Delay 0.02
Next
Call printFlag
Color 15 , 0
Locate 12 , 1
Input " Digite o numero de rodadas : " , rodadas

O código abaixo limpa a tela, desenha as pistas e os carros na posição inicial.


Cls
Call printTrack
Call printCar ( arr (1) . lineP , arr (1) . columnP ,
arr (1) . colorP )
Call printCar ( arr (2) . lineP , arr (2) . columnP ,
arr (2) . colorP )

Abaixo está o laço principal do jogo. São dois laços encadeados: o primeiro
roda tantas vezes quanto o número de rodadas, o segundo roda uma vez para
cada jogador. O jogo considera que são dois jogadores. A cada iteração é exibido
o score e é pedido a um dos jogadores que calcule o valor de uma soma. Em caso
de acerto, o jogador marca um ponto e o carro se movimenta proporcionalmente
à sua pontuação em direção à direita. Um efeito sonoro diferente é tocado em
caso de acerto ou erro.
For r = 1 To rodadas
For p = 1 To 2
Call printScore
Color 15 , 0
Locate 12 , 1
Print Spc (20)
Print Spc (20)
Print Spc (20)
Print Spc (20)
Locate 12 , 1
Color arr ( p ) . colorP , 0
Print " Rodada " ; r
Print " Player " ; p
v1 = Int ( Rnd * 100)
v2 = Int ( Rnd * 100)
msg$ = Str$ ( v1 ) + " + " + Str$ ( v2 ) + " = "
Print msg$ ;
Input " " , result

79
If result = v1 + v2 Then
arr ( p ) . scoreP = arr ( p ) . scoreP + 1
Print " Correto ! "
Play " l32 O3 cdef "
finalCol = arr ( p ) . scoreP / rodadas * maxCol
Call moveCar ( arr ( p ) . lineP , arr ( p ) . columnP ,
finalCol , arr ( p ) . colorP )
arr ( p ) . columnP = finalCol
Else
Print " Ow peste ... "
Play " l32 O2 c < ge + c "
End If
Sleep 1
Next p
Next r

Ao final da execução dos laços, o jogo atualiza o score na tela, imprime uma
bandeira quadriculada e declara o jogador com maior score como vencedor.
Call printScore
Call printFlag
Locate 21 , 30
If arr (1) . scoreP = arr (2) . scoreP Then
Color 15 , 0
Print " Deu empate !! "
Else
If arr (1) . scoreP > arr (2) . scoreP Then
vencedor = 1
Else
vencedor = 2
End If
Color arr ( vencedor ) . colorP , 0
Print " Vencedor : Player " ; vencedor
End If

Abaixo está a função que imprime a bandeira quadriculada.


Sub printFlag ()
Color 15 , 0
Locate 19 , 1
For i = 1 To 200
Print Chr$ (220) ;
Print Chr$ (223) ;
Next

80
End Sub

Abaixo está a função que exibe o score na tela.


Sub printScore ()
Locate 12 , 60
Color arr (1) . colorP , 0
Print " Score Player 1: " ; arr (1) . scoreP
Locate 13 , 60
Color arr (2) . colorP , 0
Print " Score Player 2: " ; arr (2) . scoreP
End Sub

Abaixo está a função que faz a animação dos carros.


Sub moveCar (l , c0 , c1 , colorCar )
For c = c0 To c1
Call printCar (l , c , colorCar )
_Delay 0.1
Next
End Sub

Abaixo está a função que imprime os carros em uma certa coordenada da


tela.
Sub printCar (l , c , colorCar )
Color colorCar , colorTrack
Locate l , c
Print car0$
Locate l + 1 , c
Print car1$
Locate l + 2 , c
Print car2$
End Sub

Abaixo está a função que imprime as duas pistas na parte superior da tela.
Sub printTrack ()
Color 0 , colorTrack
Locate 2 , 1
Print Spc (79)
Print Spc (79)
Print Spc (79)
Locate 6 , 1

81
Print Spc (79)
Print Spc (79)
Print Spc (79)
End Sub

6.3 Exercı́cios
1. Incremente o UFS Simulator: A Text Based RPG.
(a) Adicione novas variáveis de status, novas ações e seus efeitos sobre
as variáveis de status.
(b) No inı́cio do jogo, consulte o jogador quanto ao nı́vel de dificuldade,
o que pode influenciar o número de dias e de disciplinas.
(c) Exiba o dia da semana. Considere que o jogo começa na segunda-
feira.
(d) Use arrays para armazenar o histórico dos status e, ao final, exiba-os
em um gráfico.
2. Incremente o Corrida Aritmética.
(a) Adicione novas operações aritméticas.
(b) No inı́cio do jogo, consulte o jogador quanto ao nı́vel de dificuldade,
o que pode influenciar o número de dı́gitos e operações usadas.

82
Capı́tulo 7

Interação com o teclado e


game loop

Neste capı́tulo veremos como fazer interação com o teclado em tempo real e
como implementar um game loop para jogos de ação.

7.1 Interação com o teclado


Já vimos que é possı́vel inserir dados no programa usando a instrução INPUT.
Esta instrução pode receber valores numéricos ou strings e precisa que o usuário
digite [Enter] ao final da digitação para finalizar a inserção. Em um jogo de
ação, porém, esse tipo de entrada de dados não é a mais adequada pois é lenta
demais e uma alternativa é necessária. Nesta seção descrevemos instruções que
podem ser usadas para permitir mais interatividade no QBasic. A Tabela 7.1
lista as funções descritas nesta seção. As funções iniciadas com sublinhado são
exclusivas do QB64.

Tabela 7.1: Funções para interação com o teclado

Operação Função
Captura a última tecla pressionada INKEY$
Verifica se uma tecla está pressionada _KeyDown
Esvazia o buffer do teclado _KeyClear

A instrução abaixo armazena uma string que representa a tecla pressionada


em k$.
k$ = INKEY$

83
84
Figura 7.1: Códigos de teclas.
O código de teclas de letras, números, caracteres de pontuação e de acen-
tuação são o próprio código ASCII da tecla, mostrado na Tabela A.1 do
Apêndice A. Suas versões maiúsculas são obtidas pressionando-as juntamente
com [Shift] e também estão listadas nesta tabela. Teclas especiais como teclas
de função, [Esc], [Enter], [Insert], [Delete], [Home], [PgUp] etc e teclas quando
pressionadas junto com [Ctrl], [Alt] possuem como código uma string com duas
posições. A primeira é o caractere NUL, com código zero e a segunda é algum
caractere com código menor que 255. A Figura 7.1 mostra os códigos das teclas
especiais e combinações.
O código abaixo é um pequeno exemplo de interação com o teclado. Im-
plementa um piano com uma oitava. Quando o usuário pressiona alguma tecla
entre [q] e [i] no teclado, a nota correspondente é tocada. Observe que somente
as versões minúsculas são testadas, então, o som não sairá se for usado [Shift]
ou [CapsLock]. A tecla [q] corresponde ao C2 do piano. A depender da tecla um
expoente é obtido e a frequência de C2 é multiplicada pelo fator correspondente.
O programa sai do laço quando [Esc] é pressionado.
freqC2 = 65 ’ C2 frequency
b = 2 ^ (1/12) ’ Semitone freq . ratio

Do
k$ = InKey$
Select Case k$
Case " q " : e = 0 ’ C2 : freqDo * b ^ 0
Case " w " : e = 2 ’ D2 : freqDo * b ^ 2
Case " e " : e = 4 ’ E2 : freqDo * b ^ 4
Case " r " : e = 5 ’ F2 : freqDo * b ^ 5
Case " t " : e = 7 ’ G2 : freqDo * b ^ 7
Case " y " : e = 9 ’ A2 : freqDo * b ^ 9
Case " u " : e = 11 ’ B2 : freqDo * b ^ 11
Case " i " : e = 12 ’ C3 : freqDo * b ^ 12
Case Else : e = -1
End Select
Locate 1 , 1
Print k$ ;
If e >= 0 Then
Sound freqC2 * b ^ e , 1
End If
Loop While k$ <> Chr$ (27) ’ [ Esc ] exits

O código abaixo é um exemplo mais sofisticado de interação com o teclado.


Implementa uma nova versão do piano que exibe quais teclas estão pressionadas.
Ainda assim só toca um som de cada vez.

85
Dim arrK (1 To 32) As Integer
freqC2 = 65
b = 2 ^ (1 / 12)

Do
k$ = InKey$
arrK (1) = _KeyDown ( Asc ( " q " ) )
arrK (2) = _KeyDown ( Asc ( " w " ) )
arrK (3) = _KeyDown ( Asc ( " e " ) )
arrK (4) = _KeyDown ( Asc ( " r " ) )
arrK (5) = _KeyDown ( Asc ( " t " ) )
arrK (6) = _KeyDown ( Asc ( " y " ) )
arrK (7) = _KeyDown ( Asc ( " u " ) )
arrK (8) = _KeyDown ( Asc ( " i " ) )

id = -1
Locate 1 , 1
For i = 1 To 8
If arrK ( i ) <> 0 Then
Print " _ " ;
id = i
Else
Print Chr$ (178) ;
End If
Next i

Select Case id
Case 1: e = 0 ’ C2 : freqDo * b ^ 0
Case 2: e = 2 ’ D2 : freqDo * b ^ 2
Case 3: e = 4 ’ E2 : freqDo * b ^ 4
Case 4: e = 5 ’ F2 : freqDo * b ^ 5
Case 5: e = 7 ’ G2 : freqDo * b ^ 7
Case 6: e = 9 ’ A2 : freqDo * b ^ 9
Case 7: e = 11 ’ B2 : freqDo * b ^ 11
Case 8: e = 12 ’ C3 : freqDo * b ^ 12
Case Else : e = -1
End Select

If e >= 0 Then
Sound freqC2 * b ^ e , 0.3
_KeyClear
End If
Loop While k$ <> Chr$ (27) ’ [ Esc ] exits

86
7.2 Game loop
O game loop é um padrão de projeto muito comum em jogos [2]. O piano simples
da seção anterior é um exemplo de game loop. Essencialmente é um laço infinito.
O piano em particular sai do laço quando a tecla [Esc] é pressionada.
Do
k$ = InKey$
...
Loop While k$ <> Chr$ (27) ’ [ Esc ] exits

Em um jogo real, as reticências são substituı́das por código que processa a


entrada do teclado, mouse ou joystick, atualiza o status do jogo e renderiza a
tela. Abaixo está um exemplo elementar. As subrotinas mostradas são apenas
exemplos e precisam ser implementadas do zero.
Do
k$ = InKey$
call processInput () ’ Process input from keyboard ,
mouse or joystick
call update () ’ Update game status
call render () ’ Render screen
Loop While k$ <> Chr$ (27) ’ [ Esc ] exits

Abaixo está uma implementação de um game loop simples. O primeiro bloco


implementa a inicialização das variáveis de status de ambos os jogadores e outras
variáveis úteis, como largura w e altura h da tela, pi e velocidade v. Também é
criado um array para armazenar o status das teclas. Para os efeitos sonoros são
criadas as variáveis freqC2 e b. O tipo de dados TStatus é criado e um vetor
com duas posições deste mesmo tipo é usado para armazenar o status dos dois
jogadores.
Screen 12
Dim Shared w
Dim Shared h
Dim Shared pi
Dim Shared v
w = 640
h = 480
pi = 3.1415
v = 1 ’ Velocity

Dim arrK (1 To 8) As Integer


freqC2 = 65
b = 2 ^ (1 / 12)

87
Type TStatus
x As Integer ’ X coordinate
y As Integer ’ Y coordinate
r As Integer ’ Rotation angle . 0 is up .
c As Integer ’ Color
End Type
Dim player (1 To 2) As TStatus
player (1) . x = w / 4 ’ P . 1 starting x coordinate
player (1) . y = h / 3 ’ P . 1 starting y coordinate
player (1) . r = 90 ’ P . 1 starting rotation
player (1) . c = 4 ’ P . 1 color
player (2) . x = ( w / 4) * 3 ’ P . 2 starting x coordinate
player (2) . y = ( h / 3) * 2 ’ P . 2 starting y coordinate
player (2) . r = -90 ’ P . 2 starting rotation
player (2) . c = 2 ’ P . 2 color

Abaixo está o game loop propriamente dito. Pressionar [Esc] encerra o laço.
O vetor arrK é preenchido com o status das teclas [W], [A], [S], [D] e direcionais.
As primeiras quatro controlam o primeiro jogador e as últimas, o segundo. Em
seguida, um laço exibe o status de cada uma das oito teclas. Duas chamadas a
playerUpdate atualizam o status de cada jogador em função das teclas pressio-
nadas. Duas chamadas a playerDraw atualizam a tela. Finalmente, são gerados
efeitos sonoros a depender da tecla pressionada.
Do
k$ = InKey$
arrK (1) = _KeyDown ( Asc ( " w " ) ) Or _KeyDown ( Asc ( " W " ) )
arrK (2) = _KeyDown ( Asc ( " s " ) ) Or _KeyDown ( Asc ( " S " ) )
arrK (3) = _KeyDown ( Asc ( " a " ) ) Or _KeyDown ( Asc ( " A " ) )
arrK (4) = _KeyDown ( Asc ( " d " ) ) Or _KeyDown ( Asc ( " D " ) )
arrK (5) = _KeyDown (256 * 72)
arrK (6) = _KeyDown (256 * 80)
arrK (7) = _KeyDown (256 * 75)
arrK (8) = _KeyDown (256 * 77)

id = -1
Locate 1 , 1
For i = 1 To 8
If arrK ( i ) <> 0 Then
Print " _ " ;
id = i
Else
Print Chr$ (178) ;
End If
Next i

88
Call playerUpdate ( player (1) , arrK (1) , arrK (2) ,
arrK (3) , arrK (4) )
Call playerUpdate ( player (2) , arrK (5) , arrK (6) ,
arrK (7) , arrK (8) )

Call playerDraw ( player (1) )


Call playerDraw ( player (2) )

’ Sound effects
Select Case id
Case 1: e = 0
Case 2: e = 2
Case 3: e = 4
Case 4: e = 5
Case 5: e = 7
Case 6: e = 9
Case 7: e = 11
Case 8: e = 12
Case Else : e = -1
End Select
If e >= 0 Then
For t = 1 To 4
Sound freqC2 * b ^ e , 0.3
Sound freqC2 * b ^ ( e + 10) , 0.3
_KeyClear
Next t
End If
Loop While k$ <> Chr$ (27)

A função abaixo desenha o jogador passado como parâmetro.

Sub playerDraw ( p As TStatus )


Shared w
Shared h
PSet ( p .x , p . y )
Draw " s 10 " ’ Scale
Draw " P 0 ,0 " ’ Delete
Draw " TA " + Str$ ( p . r ) ’ Rotation angle
Draw " C " + Str$ ( p . c ) ’ Color
Draw " B L5 U2 L1 U3 R12 D3 L1 D1 R5 D2 L5 D1 R1 D3
L12 U3 R1 U2 B R5 "
Draw " P " + Str$ ( p . c ) + " ," + Str$ ( p . c ) ’ Fill
_Delay 0.05

89
End Sub

A função abaixo atualiza o status do jogador passado como parâmetro em


função do status das teclas recebidas.
Sub playerUpdate ( p As TStatus , kUp , kDown , kLeft ,
kRight )
Shared pi
Shared v
If kUp Then
p . y = p . y - v * ( Sin ( p . r * pi / 180) )
p . x = p . x + v * ( Cos ( p . r * pi / 180) )
End If
If kDown Then
p . y = p . y + v * ( Sin ( p . r * pi / 180) )
p . x = p . x - v * ( Cos ( p . r * pi / 180) )
End If
If kLeft Then
p . r = ( p . r + 45) Mod 360
End If
If kRight Then
p . r = ( p . r - 45) Mod 360
End If
End Sub

7.3 Exercı́cios
1. Modifique o piano de exemplo adicionando mais teclas.
2. Modifique o jogo dado como exemplo adicionando teclas para atirar e
desenhe os projéteis na tela.
(a) Teste a colisão do projétil com o adversário.
(b) Adicione a possibilidade das teclas ricochetearem nas extremidades
da tela. Adicione um limite de tempo ou iterações para o projétil
permanecer na tela.

90
Apêndice A

Tabela ASCII

Tabela A.1: Códigos ASCII

Dec Hex Char Dec Hex Char Dec Hex Char Dec Hex Char
0 0x00 NUL 32 0x20 64 0x40 @ 96 0x60 ‘
1 0x01 STX 33 0x21 ! 65 0x41 A 97 0x61 a
2 0x02 SOT 34 0x22 " 66 0x42 B 98 0x62 b
3 0x03 ETX 35 0x23 # 67 0x43 C 99 0x63 c
4 0x04 EOT 36 0x24 $ 68 0x44 D 100 0x64 d
5 0x05 ENQ 37 0x25 % 69 0x45 E 101 0x65 e
6 0x06 ACK 38 0x26 & 70 0x46 F 102 0x66 f
7 0x07 BEL 39 0x27 ’ 71 0x47 G 103 0x67 g
8 0x08 BS 40 0x28 ( 72 0x48 H 104 0x68 h
9 0x09 HT 41 0x29 ) 73 0x49 I 105 0x69 i
10 0x0A LF 42 0x2A * 74 0x4A J 106 0x6A j
11 0x0B VT 43 0x2B + 75 0x4B K 107 0x6B k
12 0x0C FF 44 0x2C , 76 0x4C L 108 0x6C l
13 0x0D CR 45 0x2D - 77 0x4D M 109 0x6D m
14 0x0E SO 46 0x2E . 78 0x4E N 110 0x6E n
15 0x0F SI 47 0x2F / 79 0x4F O 111 0x6F o
16 0x10 DLE 48 0x30 0 80 0x50 P 112 0x70 p
17 0x11 DC1 49 0x31 1 81 0x51 Q 113 0x71 q
18 0x12 DC2 50 0x32 2 82 0x52 R 114 0x72 r
19 0x13 DC3 51 0x33 3 83 0x53 S 115 0x73 s
20 0x14 DC4 52 0x34 4 84 0x54 T 116 0x74 t
21 0x15 NAK 53 0x35 5 85 0x55 U 117 0x75 u
22 0x16 SYN 54 0x36 6 86 0x56 V 118 0x76 v
23 0x17 ETB 55 0x37 7 87 0x57 W 119 0x77 w
24 0x18 CAN 56 0x38 8 88 0x58 X 120 0x78 x
25 0x19 EM 57 0x39 9 89 0x59 Y 121 0x79 y
26 0x1A SUB 58 0x3A : 90 0x5A Z 122 0x7A z
27 0x1B ESC 59 0x3B ; 91 0x5B [ 123 0x7B {
28 0x1C FS 60 0x3C < 92 0x5C 124 0x7C |
29 0x1D GS 61 0x3D = 93 0x5D ] 125 0x7D }
30 0x1E RS 62 0x3E > 94 0x5E ^ 126 0x7E
31 0x1F US 63 0x3F ? 95 0x5F _ 127 0x7F DEL

91
Tabela A.2: Tabela ASCII estendida, também conhecida como Code Page 437
(CP437). Fora do QBasic atualmente é usado o Unicode ao invés destes códigos.
Sı́mbolos não utilizáveis pelo LATEX foram omitidos1 .

Dec Hex Char Dec Hex Char Dec Hex Char Dec Hex Char
128 0x80 Ç 160 0xA0 á 192 0xC0 224 0xE0 α
129 0x81 ü 161 0xA1 ı́ 193 0xC1 225 0xE1 ß
130 0x82 é 162 0xA2 ó 194 0xC2 226 0xE2 Γ
131 0x83 a
^ 163 0xA3 ú 195 0xC3 227 0xE3 π
132 0x84 ä 164 0xA4 n
~ 196 0xC4 228 0xE4 Σ
133 0x85 à 165 0xA5 ~
N 197 0xC5 229 0xE5 σ
134 0x86 å 166 0xA6 ª 198 0xC6 230 0xE6 µ
135 0x87 ç 167 0xA7 º 199 0xC7 231 0xE7 γ
136 0x88 e
^ 168 0xA8 ¿ 200 0xC8 232 0xE8 Φ
137 0x89 ë 169 0xA9 201 0xC9 233 0xE9 θ
138 0x8A è 170 0xAA ¬ 202 0xCA 234 0xEA Ω
139 0x8B ı̈ 171 0xAB ½ 203 0xCB 235 0xEB δ
140 0x8C ı
^ 172 0xAC ¼ 204 0xCC 236 0xEC ∞
141 0x8D ı̀ 173 0xAD ¡ 205 0xCD 237 0xED ø
142 0x8E Ä 174 0xAE ≪ 206 0xCE 238 0xEE ε
143 0x8F Ǎ 175 0xAF ≫ 207 0xCF 239 0xEF ∩
144 0x90 É 176 0xB0 208 0xD0 240 0xF0 ≡
145 0x91 æ 177 0xB1 209 0xD1 241 0xF1 ±
146 0x92 Æ 178 0xB2 210 0xD2 242 0xF2 ≥
147 0x93 o
^ 179 0xB3 211 0xD3 243 0xF3 ≤
148 0x94 ö 180 0xB4 212 0xD4 244 0xF4
149 0x95 ò 181 0xB5 213 0xD5 245 0xF5
150 0x96 u
^ 182 0xB6 214 0xD6 246 0xF6 ÷
151 0x97 ù 183 0xB7 215 0xD7 247 0xF7 ≈
152 0x98 ÿ 184 0xB8 216 0xD8 248 0xF8 °
153 0x99 Ö 185 0xB9 217 0xD9 249 0xF9 ●
·

154 0x9A Ü 186 0xBA 218 0xDA 250 0xFA
155 0x9B ¢ 187 0xBB 219 0xDB 251 0xFB
156 0x9C £ 188 0xBC 220 0xDC 252 0xFC n

157 0x9D ¥ 189 0xBD 221 0xDD 253 0xFD ²


158 0x9E 190 0xBE 222 0xDE 254 0xFE ∎
159 0x9F f 191 0xBF 223 0xDF 255 0xFF

1 [Link] page 437;

[Link]
[Link]
[Link]

92
Figura A.1: Tabela ASCII estendida, também conhecida como Code Page 437
(CP437), usada no QBasic.

93
O código abaixo foi usado para gerar a tabela ASCII estendida mostrada na
Figura A.1.
Width 80 , 43
Cls
vBar$ = Chr$ (179)
For t = 0 To 1
Cls
For j = 0 To 3
Print vBar$ + " Dec Hex Char " ;
Next j
Print vBar$
For i = 0 To 31
For j = 0 To 3
v = 128 * t + 32 * j + i
If v < 32 Then
c$ = " "
Else
c$ = Chr$ ( v )
End If
If v < 16 Then
h$ = " 0 " + Hex$ ( v )
Else
h$ = Hex$ ( v )
End If
Print Using vBar$ + " ### 0 x " ; v ;
Print h$ ; " " ; c$ ; " ";
Next j
Print vBar$
If i = 15 Or i = 31 Then
Sleep
End If
Next i
Next t

94
Referências Bibliográficas

[1] S.K. Baumann and S.L. Mandell. QBasic. DF - Computer Applications


Series. South-Western Pub., 1997.

[2] Robert Nystrom. Game Programming Patterns. Genever Benning, 2014.


[3] D.I. Schneider. QBasic with an Introduction to Visual Basic: For Enginee-
ring, Mathematics and Sciences. Prentice Hall PTR, 1994.
[4] James M. Van Verth and Lars M. Bishop. Essential Mathematics for Games
and Interactive Applications. A. K. Peters, Ltd., USA, 2nd edition, 2008.

95

Você também pode gostar