Você está na página 1de 7
> > Home > > Missao > > Eventos > > Artigos >
> > Home > > Missao > > Eventos > > Artigos >

>>

Home

>>

Missao

>>

Eventos

>>

Artigos

>>

Livros

>>

Forum

>>

Galeria de Imagens

>>

Downloads

>>

Links Favoritos

> Downloads > > Links Favoritos Login Registrar Web Hosting By Brinkster Indique esse site.

Login

Registrar

Web Hosting By Brinkster

Indique esse site.

Login Registrar Web Hosting By Brinkster Indique esse site. Jogo ZipCode Lista Mala Direta Baixe agora
Jogo ZipCode Lista Mala Direta Baixe agora jogos de corrida, futebol estratégia e mais! Listas
Jogo
ZipCode Lista Mala Direta
Baixe agora jogos de corrida, futebol
estratégia e mais!
Listas completas e segmentadas E-mails
autorizados e Opt-in

VS.Net 2005

Empregos

VS.Net 2003

Internet

Home > Artigos

Um jogo quebra cabeças usando Generics

Enviado por carlos em terça-feira, 31 de agosto de 2004 (EST)

O Visual Studio 2005 vem com o namespace Generic. Veja nesse artigo como um simples jogo pode ser uma maneira eficiente de trabalhar com listas genéricas duplamente ligadas. Na sessão de Download voce vai encontrar o artigo e o código completos.

Construindo um jogo (quebra cabeças) usando Generics

Introdução

A primeira vez que precisei construir uma lista duplamente

ligada, estava programando em assembly da Intel. Confesso que, na ocasião, tive alguma dificuldade em entender como funcionava esse tipo de estrutura. Com o tempo, tive que fazer a mesma coisa em C e C++. Apesar do C# ser uma linguagem bem mais “suave” que essas outras citadas e ter uma ótima biblioteca de classes que auxiliam bastante o usuário, acredito que alguns desenvolvedores possam ainda ter alguma dificuldade de entender o funcionamento de uma lista duplamente ligada. Baseado nisso, resolvi criar esse pequeno jogo usando um Windows Form e C# que objetiva mostrar, visualmente, as funcionalidades oferecidas pela classe Generics ao programar uma lista duplamente ligada com uso genérico. Entender esses conceitos torna muito mais simples seu uso na implementação de programas utilizando o C# ou outras linguagens da plataforma .Net. Para rodar esse programa você terá que fazer uso do Visual Studio C# Express ou então o Visual Studio 2005 Beta 1. Você pode fazer o download de ambos no endereço

http://lab.msdn.microsoft.com

Como o jogo funciona

O funcionamento do jogo é bastante simples. A Figura 1

mostra a tela inicial do jogo que possui dois painéis e um conjunto de botões.

Figura 1. Tela inicial do jogo.

O painel superior (bege) ou painel de origem armazena as

peças que deverão ser movidas para o painel inferior (azul)

ou painel de destino, onde devem ser posicionadas corretamente e, nesse caso, formar uma palavra. O painel de origem representa a lista de peças embaralhadas e o painel de destino representa a lista onde será montada a resposta do jogo. As peças podem ser movimentadas livremente, de um painel para o outro, logicamente seguindo as regras existentes na utilização de uma lista ligada. Os vários botões são utilizados para movimentar as

Search:

vários botões são utilizados para movimentar as Search: Go Artigos Mais Populares Instalando o Windows Vista

Go

botões são utilizados para movimentar as Search: Go Artigos Mais Populares Instalando o Windows Vista O

Artigos Mais

Populares

Instalando o Windows Vistapara movimentar as Search: Go Artigos Mais Populares O Windows Vista vem ai. Como ficam questões

O Windows Vista vem ai. Como

ficam questões como instalação e compatibilidade com o hardware?

Usando Interfaces no .Netcomo instalação e compatibilidade com o hardware? Porque as interfaces são pouco usadas pelos

Porque as interfaces são pouco usadas pelos desenvolvedores? O artigo não se propõe a responder essa pergunta, mas aborda alguns pontos que podem fazer parte da resposta.

Descubra qual a versão do .Net Framework roda na maquinamas aborda alguns pontos que podem fazer parte da resposta. Com algumas linhas de código e

Com algumas linhas de código e algumas chaves do registro do Windows é possivel saber qual (ou quais) versão do .Net Framework esta instalada na maquina. Voce pode baixar o projeto completo na seção de downloads.

Links

mais Populares

Download do .NET Frameworkcompleto na seção de downloads. Links mais Populares O Microsoft® .NET Framework é um componente integral

O Microsoft® .NET Framework é

um componente integral do Windows para construir e executar

a proxima geração de aplicações e

os XML Web services. Prove uma

alta produtividade, baseado em

padrões, aplicações empresariais, ambiente multi-linguas que simplifica o desenvolvimento de

aplicações

ASP.NETque simplifica o desenvolvimento de aplicações Esse é um ótimo site onde voce encontra artigos, códigos

Esse é um ótimo site onde voce encontra artigos, códigos e componentes free para usar nas suas aplicações ASP.NET.

Treinamento ASP.NETe componentes free para usar nas suas aplicações ASP.NET. Aprenda como construir Web sites dinamicos utilizando

Aprenda como construir Web sites dinamicos utilizando o Visual Studio .NET.

Novos Artigos

Como acessar um hardware remotodinamicos utilizando o Visual Studio .NET. Novos Artigos Usando WMI para acessar uma maquina remota Construa

Usando WMI para acessar uma maquina remota

Construa um browser em poucos minutos (revisado)hardware remoto Usando WMI para acessar uma maquina remota Veja como fazer um browser usando as

Veja como fazer um browser

usando as novas funcionalidades

do Visual Studio 2005. (Pegue o

fonte completo na area de

downloads)

Instalando o Windows VistaStudio 2005. (Pegue o fonte completo na area de downloads) O Windows Vista vem ai. Como

O Windows Vista vem ai. Como

ficam questões como instalação e compatibilidade com o hardware?

peças. Observe que os botões têm títulos que representam os métodos das listas genéricas que são utilizados no programa. Desse modo, visualmente fica fácil para quem manipula o jogo, saber como cada método funciona, uma vez que o mesmo está sendo representado visualmente quando é acionado. Um outro ponto interessante é que, como o programa esta manipulando listas ligadas, algumas regras têm que ser seguidas para o programa funcionar corretamente. Por exemplo, se clicar no botão Add After (Adiciona Depois) e se não houver nenhuma peça no painel destino, o usuário receberá uma mensagem de erro dizendo que o programa não pode adicionar uma peça depois de uma outra peça, uma vez que ainda não existe nenhuma peça na janela azul. Parece obvio? Sim, mas a gente costuma não atentar para esses pequenos detalhes.

Sobre o programa

Apesar de ser um projeto apenas para demonstrar algumas

das funcionalidades do namespace Generic, aproveitei para fazer uso onde foi possivel de algumas das novidades existentes no Visual Studio 2005 como o Refactoring para

a geração rápida e padronizada de trechos de código,

partial para dividir classes grandes e FxCop para analisar o código e encontrar pontos a serem corrigidos. O objetivo foi ter uma melhor aderência às boas praticas de programação. O diagrama da Figura 2 gerado pelo Visual Studio mostra a arquitetura utilizada no programa.

Figura 2. Diagrama de Classes do programa.

Como pode ser visto no diagrama, o programa usa as classes GameForm, GameItems, Item, LinkedItems<T> e LinkedList<T>.

Classe GameForm

O formulário é gerado pela classe GameForm que

encapsula as funcionalidades que permitirão ao usuário interagir com o jogo. De acordo com a arquitetura utilizada, essa classe abstrai o modo como são manipuladas as listas que contém as peças. Dessa forma, quando um botão é acionado, o controle é passado para a classe GameItems na camada de lógica, que tem a função de manipular as listas adequadamente. Quando se deseja mover uma peça, a classe GameForm

precisa saber em qual dos dois painéis está a peça em

questão. Para isso, a classe faz uso da variável booleana sourcePanelSelected que é alterada de acordo com o evento MouseEnter o qual é disparado quando o mouse entra na região do painel, conforme mostra o código

abaixo:

Last Refreshed 6/5/2008 23:25:23

XML.com

XML.com features a rich mix of information and services for the XML community.o código abaixo: Last Refreshed 6/5/2008 23:25:23 XML.com Introducing E4X Kurt Cagle introduces us to E4X,

Introducing E4X Kurt Cagle introduces us to E4X, an XML library for JavaScript, and argues that XML Kurt Cagle introduces us to E4X, an XML library for JavaScript, and argues that XML and JSON are both indispensable parts of the web app developer's toolkit.

Data Sources as Web Services Kyle Gabhart describes WS02's Data Services, a new feature in WS02 that allows for rapid Kyle Gabhart describes WS02's Data Services, a new feature in WS02 that allows for rapid creation of web services wrapping relational, Excel, CSV, and JNDI data sources quickly and easily.

XForms Thick Clients Jack Cox explains an approach to building XForms client applications that work in a disconnected Jack Cox explains an approach to building XForms client applications that work in a disconnected environment.

jQuery and XML Uche Ogbuji returns with a new Agile Web column to explain how to use jQuery Uche Ogbuji returns with a new Agile Web column to explain how to use jQuery to process XML in JavaScript web applications.

Extended XQuery for SOA Web service orchestration is an important part of web services and service oriented architecture. Gimzewski Web service orchestration is an important part of web services and service oriented architecture. Gimzewski and Fancellu argue that XQuery is especially well-suited as an implementation language for service orchestrator components.

Copyright 2004, O'Reilly Media, Inc. Last

Refreshed 6/5/2008 23:25:23

private void sourcePn_MouseEnter(object sender, EventArgs e)

{

sourcePanelSelected = true;

}

private void targetPn_MouseEnter(object sender, EventArgs e)

{

sourcePanelSelected = false;

}

Classe Item

Essa classe armazena as funcionalidades de uma determinada peça como posição inicial da peça no painel, se selecionada ou não, etc. Vamos falar sobre seleção de itens mais adiante.

Classe LinkedItems<T>

Essa classe é derivada da classe LinkedList<T> como mostra o código:

public class LinkedItems<T> : LinkedList<T>

{

}

// codigo

Desse modo, criamos uma lista duplamente ligada genérica que pode ser utilizada para armazenar diferentes tipos de objetos, sem que haja a necessidade de alterar seu código. Daí a característica de lista genérica. Com o uso de Generic podemos construir lista fortemente tipadas aumentando a performance e obtendo um código mais limpo e fácil de dar manutençao. Apesar a classe LinkedItems herdar os métodos da classe base, resolvi criar mais alguns para facilitar a manipulação das peças no jogo. Veja também que, apesar de alguns métodos aceitarem sobrecarga de parâmetros, esse métodos trabalham com o nó da lista e, como a classe GameItems, que eu criei, manipula apenas as peças das listas, tive que implementar métodos que aceitassem apenas os itens das listas e, internamente, chamar os métodos da classe base passando os nós corretos como parametros. Veja, por exemplo, os casos dos métodos AddAfterItem e AddBeforeItem abaixo:

public LinkedListNode<T> AddAfterItem(T newItem, T item)

{

LinkedListNode<T> node = Find(newItem); return base.AddAfter(node, item);

}

public LinkedListNode<T> AddBeforeItem(T newItem, T item)

{

LinkedListNode<T> node = Find(newItem); return base.AddBefore(node, item);

}

Como os métodos da classe base AddAfter e AddBefore só aceitam o primeiro parâmetro como sendo um objeto do tipo LinkedListNode, então foi necessário primeiro achar o node correspondente ao item e, só então, chamar a o método da classe base. Um outro método também adicionado a classe LinkedItems é o método GetSibilingItem que retorna o item vizinho ao item passado como referencia. Esse método também tem como segundo parâmetro um booleano que indica se o item a ser encontrado é o vizinho antes ou depois da referencia. Veja no código abaixo:

public T GetSibilingItem(T item, bool forward)

{

 

// porque a lista é duplamente ligada, podemos facilmente // percorrer toda a lista para frente ou para tras LinkedListNode<T> node = null; Nullable<T> retNull = null;

node = Find(item); if (node == null)

return default(T);

else

{

// procura para frente if (forward)

{

node = node.Next;

}

// procura para tras

else

{

node = node.Previous;

}

}

// se nao achar, retorna nulo if (node == null) return default(T); else return node.Value;

}

Como você pode ver, uma das grandes vantagens de uma lista duplamente ligada é que ela pode ser facilmente percorrida para frente e para trás. Nesse caso, isso se torna uma grande dor de cabeça em uma linguagem de baixo nível, onde o programador deve se preocupar em atualizar os ponteiros da lista, uma vez que eles apontam para frente e para trás. Qualquer erro no uso incorreto desses ponteiros e você corre o risco de não mais encontrar seus dados. No C#, que utiliza código gerenciado, você não tem que se preocupar com esses detalhes. Um outro ponto interessante desse método é o uso da classe Nullable<T>:

return default(T);

Veja que, se o item que será usado como referencia não for encontrado na lista, o método deve retornar null. A questão é: como retornar null para um objeto T genérico? Se no código eu forçar o retorno de null, o compilador retorna um erro dizendo que não pode converter o null para o tipo T a ser retornado. A solução é utilizar o valor default do tipo ou, default(T). O valor default é também conhecido como valor nulo do tipo nullable. Ocorre uma conversão implícita entre o null literal para qualquer tipo nullable e essa conversão produz o valor nulo para o tipo.

Classe GameItems

Para tornar a classe mais “limpa”, utilizei a palavra chave partial que permite quebrar uma classe, estrutura ou interface em vários arquivos. Essa classe tem uma função fundamental no funcionamento do programa, pois é ela que vai fazer uso dos métodos disponíveis na lista ligada usada nesse programa. Ao ser instanciada, a classe GameItems cria as duas listas

ligadas do tipo LinketItems<T>, que recebem como parâmetro a classe Item, como mostra o código:

public GameItems(GameForm frm)

{

 

//savedItemsLocation = new List<Item>(); // creates a target linked list targetListItems = new LinkedItems<Item>(); // creates a source linked list sourceListItems = new LinkedItems<Item>();

// save the initial appearance of the game SaveSourceLocationAndItems(frm);

}

Veja que as listas criadas targetListItems e sourceListItems são fortemente tipadas, pelo fato da lista genérica ter sido criada utilizando como parâmetro um tipo pré-definido. Isso torna o uso dessas listas bem mais simples porque não há a necessidade de utilizar “cast” na retirada de um elemento da lista, uma vez que a lista só aceita um único tipo de item. A classe GameItems também recebe, no construtor, uma referencia ao formulário, que é passada para o método SaveSourceLocationAndItems, permitindo salvar as posições iniciais de todas as peças existentes no painel de origem. Um outro ponto interessante é que a classe GameItems manipula as peças do jogo trocando as peças de uma lista para outra e atualizando suas posições, enquanto que a classe GameForm manipula as peças nos painéis.

Adicionando e retirando um item

Adicionar um item ao inicio ou final de uma lista é um procedimento bem simples e o próprio código é auto-explicativo nesse sentido. Veja que, tanto para adicionar como apagar um elemento da lista, há a necessidade de atualizar os “ponteiros” dessa lista, o que é feito internamente pelo .Net Framework. Em uma linguagem de mais baixo nível como C++, C ou assembly, isso tem que ser feito na mão pelo programador. Vamos verificar então a adição de um item ANTES de um outro item, como mostra o código:

public PictureBox AddPieceBefore()

{

Item selectedSrcItem = null; Item selectedTgtItem = null;

// pega o item selecionado na lista de origem selectedSrcItem = GetSelectedItem(sourceListItems); // pega o item selecionado na lista de destino selectedTgtItem = GetSelectedItem(targetListItems);

// se null, precisa selecionar um item

if (selectedSrcItem != null && selectedTgtItem != null)

{

// adiciona item ao final da lista targetListItems.AddBeforeItem(selectedTgtItem, selectedSrcItem); // remove item da lista de origem sourceListItems.Remove(selectedSrcItem); // retira a seleção do item selectedSrcItem.IsSelected = false; selectedTgtItem.IsSelected = false;

// tenta deslocar todos os item para acomodar o item adicionado Point nextPosition = solutionPosition; // atualiza a lista

UpdatePositionForEntireList(targetListItems, nextPosition);

}

else return null; return selectedSrcItem.PicItem;

}

Quando se vai adicionar um item antes de um outro, algumas condições têm que ser satisfeitas. Veja que o trecho de código abaixo:

if (selectedSrcItem != null && selectedTgtItem != null)

verifica se existe um item selecionado para ser retirado da lista de origem e se existe um item selecionado na lista de destino para ser usado como referencia, conforme o método AddBeforeItem que pede esses dois parâmetros. Se a inserção do novo item for feita com sucesso, o item é removido da lista de origem e as peças são tornadas não selecionadas. Após a inserção, há ainda a necessidade de atualizar as posições dos itens, o que equivaleria a atualização de seus ponteiros, conforme citado acima. O método UpdatePositionForEntireList faz essa atualização, acomodando cada item em seu devido lugar.

O método AddAfterItem tem um funcionamento

semelhante, mudando apenas o lugar onde será feita a inserção, ou seja, adiciona depois. Veja que para os métodos de remoção, não existe um RemoveAntes ou RemoveDepois. Uma vez que o usuário escolhe uma peça para ser removida, não faz sentido, nesse programa, ter um método que remove a peça que está antes ou depois da peça escolhida. Mas, se fosse necessário, logicamente que isso poderia ser implementado.

Selecionando um item

Como já foi comentado acima, dependendo da operação a ser executada no jogo, há a necessidade de selecionar uma ou duas peças. Esse pedido de seleção é feita pelo método PieceItem_Click da classe GameForm que, por sua vez, repassa o pedido para o método SelectPicItem da classe GemeItems. A mudança para situação de item selecionado é feita pela propriedade IsSelected da classe Item, conforme mostrado no código abaixo:

public bool IsSelected

{

get{ return selected;}

set

{

selected = value; // if the item is selected, change its appearence // to notify the user if (selected) item.BorderStyle = BorderStyle.FixedSingle; else item.BorderStyle = BorderStyle.None;

}

}

Conclusão

O projeto mostra de forma visual e através de código como

é simples a manipulação de uma lista duplamente ligada

usando o namespace Generic. A possibilidade de utilização de uma lista fortemente tipada também facilita bastante a

programação do sistema. Como o objetivo principal foi mostrar de forma visual esses conceitos, logicamente que algumas melhorias que poderiam ser feitas se o objetivo fosse criar um jogo acabaram não acontecendo. Veja que, os botões poderiam simplesmente ser retirados e

a movimentação das peças poderia ser feita

exclusivamente pelo mouse. Mas ai deixaríamos de ter um tratamento visual. Boa diversão!

Home

Por Carlos Roberto Lacerda Analista de Sistemas Sênior

carlos@byteshift.com

www.byteshift.com

de Sistemas Sênior carlos@byteshift.com www.byteshift.com Avise-me quando um novo comentário for colocado Adicione

Avise-me quando um novo comentário for colocado

Adicione seu Comentario

|

Missao

|

Eventos

| Artigos

| Livros

| Forum

| Galeria de Imagens

| Downloads

| Links Favoritos