UFES INFO9300 - Introdução à Computação 1
Universidade Federal do Espírito Santo
INFO9300 - Introdução à Computação
25/05/2015
Exemplo de código em linguagem de montagem (Assembly)
1. Torre de Hanoi:
1.1. Torre de Hanói é um "quebra-cabeça" que consiste em uma base contendo
três pinos, em um dos quais são dispostos alguns discos uns sobre os outros,
em ordem crescente de diâmetro, de cima para baixo. O problema consiste em
passar todos os discos de um pino para outro qualquer, usando um dos pinos
como auxiliar, de maneira que um disco maior nunca fique em cima de outro
menor em nenhuma situação. O número de discos pode variar sendo que o
mais simples contém apenas três.
A Torre de Hanói tem sido tradicionalmente considerada como um
procedimento para avaliação da capacidade de memória de trabalho, e
principalmente de planejamento e solução de problemas.
2. Implementação Assembly (nível 4):
2.1. Código Assembly:
1 INCLUDE C:/Irvine/Irvine32.inc
.data
welcome1 byte "Torre de Hanoi",0
welcome2 byte "Entre com o número de discos: ",0 numOfDiscs byte 0
tempDisc byte ? currentDisc db ?
leftstack byte 10 dup(0) middlestack byte 10 dup(0) rightstack byte 10 dup(0) .code
main proc
call WelcomeToGame exit
main endp
take proc ; Retira o disco usando eax .if currentDisc != 0 ; Não permitido ret
.endif
.if eax == 0 ; Pega o disco do topo mov edi, offset leftstack
call myPop
.elseif eax == 1 ; Move o disco para o meio mov edi, offset middlestack
call myPop
.elseif eax == 2 ; Move o disco para a direita mov edi, offset rightstack
call myPop .endif ret take endp
place proc ; Empilha o disco usando eax .if currentDisc == 0 ; Não permitido ret
.endif
.if eax == 0 ; Move para a esquerda mov edi, offset leftstack
call myPush
.elseif eax == 1 ; Move para o meio mov edi, offset middlestack call myPush
.elseif eax == 2 ; Move para a direita mov edi, offset rightstack
call myPush .endif
ret place endp
myPop proc uses edi ; seleciona o primeiro não zero a direita mov ecx, 9 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
UFES INFO9300 - Introdução à Computação 3 55 loop L1 mov bl, [edi] movzx eax, bl call WriteInt call CRLF L2:
add edi, ecx mov bl, 0 mov [edi], bl mov currentDisc, al ret
myPop endp
myPush proc uses edi ; coloca o valor no ultimo zero a direita mov ecx, 9
L1:
mov bl, [edi + ecx] movzx eax, bl cmp eax, 0 jnz L2 loop L1 L2:
add edi, ecx inc edi
movzx edx, currentDisc mov [edi], edx
mov currentDisc, 00 ret
myPush endp
myPeek proc uses edi ; coloca o primeiro não zero no vetor mov ecx, 9
L1:
mov bl, [edi + ecx] movzx eax, bl cmp eax, 0 jnz L2 loop L1 L2: mov tempDisc, al ret myPeek endp
WelcomeToGame proc ; Tela inicial mov edx,offset welcome1
call writestring call crlf
mov edx,offset welcome2 call writestring call readint mov numOfDiscs,al mov ecx, 0 mov esi, 0 mov cl, numOfDiscs
mov esi, offset leftstack Looper: mov [esi], cl dec bl inc esi Loop Looper ret 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
113 WelcomeToGame endp end main
114
2.2.
Como seria implementar uma solução para este jogo em linguagem de
montagem (Assembly) para processadores atuais, por exemplo para
processadores I com Windows 7
?
Passo a passo:
i. Há um aspecto importante a ser abordado com relação ao Assembly: A
linguagem Assembly é dependente do processador da sua máquina bem como do SO, portanto os montadores a serem usados por cada um serão diferentes; ii. Normalmente a escrita do código pode ser feita em qualquer editor de texto,
o Notepad++ (download aqui) é uma opção interessante, que já tem algumas funções de apoio a programação;
iii. Para montar e "executar" programas de processadores Pentium e anteriores (pertencentes à família x86), nas atuais máquinas é necessário emular estes processadores. Para esta tarefa pode-se usar o DosBox (download aqui), juntamente com versões apropriadas do MASM;
iv. Por outro lado, é interessante que se observem estas variações nos diversos conjuntos Processador/SO disponíveis entre nós;
v. Obtenha então, um montador adequado à configuração do seu computador, no meu caso aqui, usei um montador (Assembler) para Intel i5 64bits. Então baixei o Microsoft Macro Assembler (MASM) 64 bits da página da Microsoft (aqui). É importante lembrar que para o meu caso foi necessário instalar o
Microsoft Visual Studio Express (na realidade o MASM já está embutido nele); vi. No meu caso instalei a versão 2013 do Ms Visual Studio Express Community,
que é gratuita;
vii. Para facilitar o trabalho utilizei uma biblioteca auxiliar, que pode ser encontrada aqui. No site deste professor estão diversas dicas e usos do Assembly para PCs com processadores x86, tanto para Windows quanto para Linux. A instalação é bastante simples;
viii. Neste caso em questão posso gerar código tanto para 32 quanto para 64 bits, para este exemplo escolhi gerar o código para 32 bits;
ix. Siga o passo a passo para criar um projeto em Assembly: a. Abra o Visual Studio e clique em File ->New -> Project; b. Na árvore selecione C++ e clique em Empty Project; c. Grave seu projeto com o nome de Hanoi;
d. A partir deste momento, aparecerá na lateral direita da tela do VS o Solution Explorer. Clique então em Hanoi como o botão direito e clique em Build Dependencies -> Build Customizations...; e. Na lista selecione masm;
UFES INFO9300 - Introdução à Computação 5 f. No Solution Explorer localize a pasta Source Files e com o botão
direito clique em Add -> New Item;
g. Na árvore localize Visual C++ -> Utility e selecione Text File; h. Crie o novo arquivo chamado Hanoi.asm;
i. Coloque neste arquivo o código deste exercício;
j. Grave seu arquivo com o nome de hanoi.asm por convenção os arquivos em linguagem de montagem possuem a extensão .asm; k. Grave o seu projeto;
x. Neste momento seu projeto está editado, mas ele ainda não poderá ser montado pois é necessário configurar as informações do seu projeto; xi. No meu caso a configuração foi feita como se segue:
a. Selecione Hanoi no Solution Explorer e com o botão direito clique em Properties;
b. Configure as propriedades conforme a seguir (atenção para a árvore do lado esquerdo):
c. Aplique as modificações e clique em Ok; xii. Monte o programa por meio do seguinte comando:
a. No Visual Studio, a montagem do programa é feita por meio do botão direito sobre o projeto no Solution Explorer e clicando em Build; b. Caso você esteja usando outro montador, deverá executar a
montagem conforme recomendado para o seu caso. Na maior parte dos casos é possível fazer isso diretamente via prompt de comando; c. A execução do programa direto no VS se dá diretamente clicando-se
em Ctrl+F5;
d. Outra opção é executar o seu programa via Debug, para visualizar o funcionamento do mesmo. Para isso basta colocar o cursor na linha 11 e teclar F5 para iniciar o Debug. O passo a passo deverá ser feito com F10. É interessante ativar a visão dos registradores e a memória clicando em Debug -> Window -> Registers;
e. Para visualizar as mensagens de Debug corretamente clique em Tools -> Options e faça a seguinte configuração:
UFES INFO9300 - Introdução à Computação 9 f. Ou a exeucução poderá ser feita diretamente no SO. Para isso, localize
na pasta Debug do seu projeto o arquivo hanoi.exe já montado e compilado, basta então executá-lo via prompt de comando: Hanoi.exe
3. Implementação C (nível 5):
3.1. Código C:
1 /*
=========================================================================== Nome : hanoi.c
Autor : Beatriz Franco Martins Souza Versão : 1.0
Copyright : Código aberto
Descrição : Hanoi Tower recursivo
=========================================================================== */
/** Incluindo as bibliotecas necessárias */ #include <stdio.h>
#include <stdlib.h>
/**
* Núcleo da resolução com impressão da sequência ótima de movimentos * para transferir os discos da orgigem para o destino.
*
* Lista de parâmetros da função:
* @param qtd_discos Quantidade de discos a movimentar. * @param origem Número da torre origem.
* @param destino Número da torre destino. * @param temp Número da torre temporária. */
void resolve(int qtdDiscos, int origem, int destino, int temp) {
/** Número de ordem de cada movimento na sequência de resolução. */ static int rank = 0;
if (qtdDiscos > 0) {
resolve(qtdDiscos-1, origem, temp, destino); /** Impressão na tela de cada movimento */
printf("%4d ) %c --> %c\n", ++rank, '@' + origem, '@' + destino); resolve(qtdDiscos-1, temp, destino, origem);
} } /**
* Função principal que invoca o núcleo da resolução com o parâmetro * fornecido na linha de comando e constantes que caracterizam o problema. *
* @param Quantidade de discos a movimentar entre as 3 pilhas. */
int main(void) { int numDiscos = 0; scanf("%d", &numDiscos); resolve(numDiscos, 1, 3, 2); 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
UFES INFO9300 - Introdução à Computação 11
3.2. Como seria implementar uma solução para este jogo em uma linguagem de
alto nível, por exemplo C?
Passo a passo em C:i. Você pode utilizar o próprio Notepad++ para edição, mas para facilitar utilize um IDE, capaz de compilar o código C, por exemplo o Eclipse Luna (download
aqui para 64 bits);
ii. Para instalar o Eclipse basta descompactar o arquivo baixado na pasta C:\Eclipse_cpp (atenção, não use espaços em branco neste path); iii. Crie um atalho para o Eclipse na sua Área de Trabalho;
iv. O Eclipse, funciona somente como um editor, portanto ele necessita do compilador para que as tarefas sejam executadas corretamente. Faça o download aqui e instale o MinGW toolchain (no meu caso usei a versão mais recente para 64 bits);
v. Siga o passo a passo para configurar corretamente o MinGW no Eclipse: a. Instale o MinGW normalmente;
b. Instale-o no path C:\MinGW;
c. No Eclipse clique em Window->Preferences; d. Abra a árvore C/C++ -> Build -> Enviroment; e. Clique em Select... e localize o PATH;
f. Adicione o caminho do MinGW ao final do path: <C:\MinGw\bin;C:\MinGw\msys\1.0\bin;>;
g. Clique em Ok e aplique a operação;
h. Abra a árvore New C/C++ Project Wizard -> Makefile Project;
i. Na aba Binary Parsers e marque PE Windows Parser (para usuários do Windows) ou Cygwin PE Parser (para usuários do Linux);
j. Aplique a alteração;
k. Abra a árvore General -> Workspace; l. Ajuste a codificação do texto para UTF-8;
m. Para usuários do ambiente Linux, é necessário configurar também o delimitador de fim de linha;
vi. Siga o passo a passo para criar um projeto em C:
a. Com o botão direito na área de projeto clique em New -> C Project; b. Selecione Hello World ANSI C Project e MinGW gcc;
c. Nomeie o projeto como Hanoi e clique em Finalizar;
d. Troque o código gerado pelo Eclipse pelo código deste exercício; e. Grave o seu projeto;
vii. Depois do código fonte editado, grave-o como hanoi.c;
viii. Como C é uma linguagem compilada (traduzida), compile o código no próprio IDE e o arquivo hanoi.exe será criado, para isso selecione o projeto e clique no ícone do martelo localizado na barra de tarefas superior;
ix. Teste a execução pelo próprio Eclipse, , para isso selecione o projeto e clique no ícone da seta verde localizado na barra de tarefas superior;
x. Execute o programa no prompt de comando e veja o resultado: Hanoi.exe
UFES INFO9300 - Introdução à Computação 13
4. Implementação Java (nível 5):
4.1. Código Java:
1 /*
=========================================================================== Nome : hanoi.java
Autor : Beatriz Franco Martins Souza Versão : 1.0
Copyright : Código aberto
Descrição : Hanoi Tower não recursivo
=========================================================================== */
package br.ufes.inf.hanoi;
// Incluindo as bibliotecas necessárias import java.util.ArrayList;
import java.util.Collections;
import java.util.InputMismatchException; import java.util.List;
import java.util.Scanner;
// Classe Disco: Para cada disco a ser movimentado class Disco implements Comparable<Disco>{
Integer index; String movimento;
Disco(int index,String movimento){ this.index=index;
this.movimento=movimento; }
public int compareTo(Disco o) { return index.compareTo(o.index); }
}
// Classe Hanoi: Para tratamento dos movimentos public class Hanoi {
private int qtDiscos; //para impares
private String sequenciaImpares[] = {"A-->C", "C-->B", "B-->A"}; //para pares
private String sequenciaPares [] = {"A-->B", "B-->C", "C-->A"}; private List<Disco> arrayDiscos = new ArrayList<Disco>();
@SuppressWarnings("resource") // Leitura dos dados no console public void lerDados() {
System.out.println("Digite a quantidade de discos"); try{
Scanner rc = new Scanner(System.in);
qtDiscos = rc.nextInt();
}catch(InputMismatchException e){ System.out.println
("Amigão! É fácil, digite o número de discos por favor!"); lerDados(); } } 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
55
// Calcula os movimentos public void hanoi() {
int maxP=(int) Math.pow(2, qtDiscos); int y = 1;
int pos =1;
while(y <= qtDiscos ){
int ctPulos = (int) Math.pow(2, y); pos*=2;
if(y==1){ pos=1; }
if(qtDiscos%2==0){
populaArrayPares(pos,ctPulos,maxP,y); }else{
populaArrayImpares(pos,ctPulos,maxP,y); }
y++; } }
// Preenche o vetor de pares
private void populaArrayPares(int pos,int intervalos, int maxP,int y){ int index = 0;
if(y%2==0){
for (int i = pos; i <= maxP; i+=intervalos) { Disco d = new Disco(i, sequenciaPares[index]);
arrayDiscos.add(d); index++; if(index>2){ index=0; } } }else{
for (int i = pos; i < maxP; i+=intervalos) { Disco d = new Disco(i, sequenciaImpares[index]);
arrayDiscos.add(d); index++; if(index>2){ index=0; } } } }
// Preenche o vetor de pares
private void populaArrayImpares(int pos,int intervalos, int maxP,int y){ int index = 0;
if(y%2==0){
for (int i = pos; i < maxP; i+=intervalos) { Disco d = new Disco(i, sequenciaImpares[index]);
arrayDiscos.add(d); index++; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
UFES INFO9300 - Introdução à Computação 15 113 for (int i = pos; i <= maxP; i+=intervalos) {
Disco d = new Disco(i, sequenciaPares[index]);
arrayDiscos.add(d); index++; if(index>2){ index=0; } } } }
// Função principal efetua a leitura do número de discos, calcula os // movimentos e exibe o resultado no console
public static void main(String[] args) { Hanoi h = new Hanoi();
h.lerDados(); h.hanoi();
Collections.sort(h.arrayDiscos);
for (Disco d : h.arrayDiscos) {
System.out.println("execute: "+d.index+" "+d.movimento); } } } 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
4.2. Como seria implementar uma solução para este jogo em uma linguagem de
alto nível, por exemplo Java?
Passo a passo em Java:
i. Da mesma maneira que nos outros casos, você pode utilizar um IDE, como o
Eclipse Luna (download aqui para 64bits), ou o próprio Notepad++ para edição;
ii. Para instalar o Eclipse basta descompactar o arquivo baixado na pasta C:\Eclipse_std (atenção, não use espaços em branco neste path); iii. Crie um atalho para o Eclipse na sua Área de Trabalho;
iv. Para que seja possível trabalhar com o Java corretamente é necessário que o JDK esteja instalado na sua máquina (download aqui);
v. Siga o passo a passo para criar um projeto Java:
a. Com o botão direito na área de projeto clique em New -> Java Project; b. Selecione o projeto e com o botão direito clique em New -> Package e
nomeie como br.ufes.inf.hanoi;
c. Nomeie o projeto como Hanoi e clique em Finalizar;
d. Selecione o pacote e com o botão direito clique em New -> Class e copie código deste exercício;
e. Grave o seu projeto;
vi. Como Java é uma linguagem interpretada, basta que seu computador possua a JVM para que você possa executar seu programa;
vii. Se você editou no IDE, poderá ver a execução no próprio IDE, mas se editou no Notepad++ deverá executar via prompt de comando;
ix. Para compilar via prompt de comando use: javac Hanoi.java
x. Após a compilação haverá duas classes geradas (Hanoi.class e Disco.class); xi. Execute o programa no prompt de comando e veja o resultado:
UFES INFO9300 - Introdução à Computação 17