sexta-feira, 26 de abril de 2013

Tem troco

Para hoje um pequeno programa que dá troco, bem dar não dá mas calcula o troco a dar em função das moedas disponíveis.

Neste projeto vamos utilizar o novo Visual Studio 2012.



Como era de se esperar vamos iniciar um projeto novo:


Agora adicionamos os seguintes elementos:
 - um botão para calcular as moedas a dar de troco
 - um botão para repor o número de moedas iniciais disponíveis
 - uma textbox para introduzir o valor a pagar
 - uma textbox para introduzir o valor entregue
 - umas labels para informar o utilizador do que deve introduzir e outra para mostrar o troco
 - por fim uma grelha para mostrar os valores das moedas e as quantidades disponíveis de cada uma.

A janela principal do programa fica assim:


Agora o código, primeiro o evento load do formulário, neste vamos definir os valores das moedas e as respetivas quantidades

Para guardar estes valores vamos necessitar de uma variável definida ao nível do formulário, logo abaixo da definição da class:

Public Class Form1
    Public moedas(0 To 7, 0 To 2) As Double


Assim no load fica:


        'valor das moedas
        moedas(0, 0) = 0.01
        moedas(1, 0) = 0.02
        moedas(2, 0) = 0.05
        moedas(3, 0) = 0.1
        moedas(4, 0) = 0.2
        moedas(5, 0) = 0.5
        moedas(6, 0) = 1
        moedas(7, 0) = 2
        'número de moedas
        moedas(0, 1) = 5
        moedas(1, 1) = 5
        moedas(2, 1) = 5
        moedas(3, 1) = 5
        moedas(4, 1) = 5
        moedas(5, 1) = 5
        moedas(6, 1) = 5
        moedas(7, 1) = 5
        'moedas dadas como troco
        moedas(0, 2) = 0
        moedas(1, 2) = 0
        moedas(2, 2) = 0
        moedas(3, 2) = 0
        moedas(4, 2) = 0
        moedas(5, 2) = 0
        moedas(6, 2) = 0
        moedas(7, 2) = 0

Como podemos verificar na matriz temos três colunas: a primeira para o valor facial das moedas, a segunda para a quantidade de moedas disponíveis e a terceira para a quantidade de moedas a dar de troco.

Precisamos, ainda, de uma função para atualizar a grelha:

    Sub grelha()
        Dim l, c As Integer

        If Me.DataGridView1.Rows.Count < moedas.Length / 3 Then

            For l = 0 To 7
                Me.DataGridView1.Rows.Add()
                For c = 0 To 2
                    Me.DataGridView1.Rows(l).Cells(c).Value = moedas(l, c)
                Next
            Next
        Else
            For l = 0 To 7
                For c = 0 To 2
                    Me.DataGridView1.Rows(l).Cells(c).Value = moedas(l, c)
                Next
            Next
        End If

    End Sub

Esta função começa por verificar se a grelha está ou não preenchida, se sim atualiza os valores senão adiciona linhas e atualiza os valores.
A função deve ser chamada no evento load, mesmo no final.


O botão para repor é muito simples:

    Sub repor()
        'número de moedas
        moedas(0, 1) = 5
        moedas(1, 1) = 5
        moedas(2, 1) = 5
        moedas(3, 1) = 5
        moedas(4, 1) = 5
        moedas(5, 1) = 5
        moedas(6, 1) = 5
        moedas(7, 1) = 5
        'moedas dadas como troco
        moedas(0, 2) = 0
        moedas(1, 2) = 0
        moedas(2, 2) = 0
        moedas(3, 2) = 0
        moedas(4, 2) = 0
        moedas(5, 2) = 0
        moedas(6, 2) = 0
        moedas(7, 2) = 0

        grelha()

    End Sub

Primeiro altera os valores disponíveis de cada tipo de moeda e por fim limpa os valores referentes às moedas retiradas como troco.

Agora o código do botão calcular:

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim v_pagar, v_entregue, v_troco, s_troco, m As Double

        If IsNumeric(TextBox1.Text) = False Then Exit Sub
        If IsNumeric(TextBox2.Text) = False Then Exit Sub

        Double.TryParse(TextBox1.Text, v_pagar)
        Double.TryParse(TextBox2.Text, v_entregue)
        v_troco = v_entregue - v_pagar
        v_troco = Math.Round(v_troco, 2)
        Me.Label3.Text = v_troco

        If Me.Label3.Text = "0" Then Exit Sub

        s_troco = 0
        m = 7
        Do While s_troco < v_troco And m >= 0
            If s_troco + moedas(m, 0) <= v_troco And moedas(m, 1) > 0 Then
                s_troco = s_troco + moedas(m, 0)
                moedas(m, 1) -= 1
                moedas(m, 2) += 1
            Else
                m -= 1
            End If
        Loop
        If s_troco < v_troco Then
            MessageBox.Show("Não existem moedas suficientes para processar o troco!")
        End If
        grelha()

    End Sub
Esta função começa por tentar retirar os valores das textboxes, depois calcula o valor do troco.
De seguida arredonda o troco só para duas casas decimais e se o troco foi diferente de 0 então vamos procurar moedas até atingir o valor do troco.
Para dar o troco começamos pelo fim da matriz à procura das moedas de maior valor até não termos mais moedas ou até satisfazermos o valor do troco.

E pronto, mais um projeto disponível aqui.


quinta-feira, 18 de abril de 2013

Atualizar uma página html com jquery

Neste post vamos implementar uma página web que atualiza o seu conteúdo sem ter de recarregar a página toda.

A estrutura básica da página tem as seguintes pastas:
\ajax - pasta com ficheiro php que pesquisa a base de dados e devolve o valor encontrado
\db - pasta com ficheiro php com instruções para ligação à base dados
\js - pasta com código javascript que utiliza a livraria JQuery para atualizar o ficheiro index.html com os dados devolvidos pelo ficheiro php que pesquisa a base de dados.

O resultado final será:



Se a página fosse construída somente com código html ao clicar no botão "Pesquisar" o browser seria redirecionado para outra página ou para a mesma mas fazendo um reload.

Para implementarmos a página sem reload utilizamos código que vai alterar o DOM da página com os dados recolhidos na base de dados.

Começamos pela página principal, index.html, com o seguinte código:


<!DOCTYPE html>
<html>
<head>
<title>AJAX Database</title>
</head>
<body>
Nome: <input type="text" id="name">
<input type="submit" id="name-submit" value="Pesquisar">
<div id="name-data"></div>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script src="js/global.js"></script>
</body>
</html>


Neste código é importante recordar os nomes do botão (name-submit), o nome do campo de introdução de texto (name) e por fim o nome da div (name-data). Estes nomes são importantes porque vamos ter de nos referir a eles no código javascript.

Antes de continuarmos vamos criar a base de dados MySQL que vai conter o dados a apresentar.

Primeiro criar a base de dados com o seguinte comando:

create database ajaxdb;

Depois criar uma tabela com nome names, assim:

create table names(name_id int,name varchar(50),location varchar(50));

Agora que temos a base de dados podemos continuar.

Olhando para o código html apresentado encontramos uma referencia a um ficheiro global.js que se encontra na pasta js. Este ficheiro vai, utilizando javascript, implementar o método post através do controlo do clique com o rato no botão.

O código javascript tem uma particularidade com a qual estou pouco à vontade que são as funções callback anónimas, desde que comecei a ver código javascript com este tipo de funções fiquei espantado! Como é que alguém consegue perceber aquilo?! Assim vou apresentar duas versões do ficheiro global.js, uma sem funções anónimas muito mais fácil de entender e outra com as funções anónimas.

Ficheiro global.js, versão sem funções anónimas:


$('input#name-submit').on('click',f_click());

function f_click(){
var name = $('input#name').val();

if($.trim(name)!=''){
$.post('ajax/name.php',{name: name},f_recebe(data));
}
}

function f_recebe(data){
$('div#name-data').text(data);
}


A primeira linha associa a função f_click ao evento click do botão, ou seja, quando o utilizador clica no botão é chamada a dita função.

A função f_click começa por recolher o valor do campo de texto e guarda-o na variável name, como pretendemos que o valor esteja preenchido utilizamos a função trim para remover espaços em branco antes de verificar se está em branco.

Se tudo correu bem e existe um valor para pesquisar na base de dados utilizamos a função post para receber valores do servidor chamando uma página, neste caso a página name.php e passando o parâmetro name para a página. Definimos, ainda, uma função callback (f_recebe) para receber o resultado do servidor através do parâmetro data.

Dentro da função f_recebe colocamos o valor de data na div.

Antes de avançarmos para o PHP aqui fica o código da versão com funções callback anónimas:

$('input#name-submit').on('click',function(){
var name = $('input#name').val();

if($.trim(name)!=''){
$.post('ajax/name.php',{name: name},function(data){

$('div#name-data').text(data);
});
}
});



Agora o PHP, a página name.php, tem o seguinte código:

<?php
if(isset($_POST['name'])===true && empty($_POST['name'])===false){
require '../db/connect.php';

$query = mysql_query("
SELECT names.location
FROM names
WHERE names.name='".mysql_real_escape_string(trim($_POST['name']))."'
");
echo (mysql_num_rows($query)!==0) ? mysql_result($query,0,'location') : 'Nome não encontrado';
}
?>


Primeiro verificamos se o parâmetro name está preenchido, em caso afirmativo fazemos o require do ficheiro connect.php (ver código abaixo) e consultamos a base de dados com um select. O resultado da consulta é devolvido com a função echo.

O código do ficheiro connect.php é simples, estabelece a ligação à base de dados:

<?php
mysql_connect('localhost','utilizador','password');
mysql_select_db('ajaxdb');
?>

Assim temos uma página que consulta a base de dados e coloca o resultado dinamicamente na página sem recarregar a página, ao estilo gmail.




Fontes:
http://api.jquery.com/jQuery.post/
http://www.w3schools.com/jquery/jquery_syntax.asp
http://www.youtube.com/watch?v=Yb3c-HljFro

sábado, 13 de abril de 2013

Game of 15

Toda a gente conhece o jogo de puzzle em que existe um espaço livre para mover as peças para os lugares certos. Para quem não conhece pode sempre clicar aqui.

Imagem da wikipedia

Hoje vamos resolver o jogo em C.



Para começar utilizamos uma matriz 4x4 para o jogo.

int jogo[4][4];

Além desta matriz vamos definir outra para armazenar a solução do jogo.

int solucao[4][4];

Antes de mais nada criamos uma função para limpar e preparar a matriz de jogo e a matriz da solução:

//prepara a matriz do jogo
void limpar(void)
{
int l,c,conta=1;

    n_jogadas=0;
    for(l=0;l<4;l++){
        for(c=0;c<4;c++){
            jogo[l][c]=conta;
            solucao[l][c]=conta;
            conta++;
        }
    }
    jogo[3][3]=0;
    solucao[3][3]=0;
}

Também precisamos de uma função para mostrar o estado da matriz do jogo, assim:

//mostra a matriz do jogo
void mostrar(void)
{
int l,c;
    system("cls");
    for(l=0;l<4;l++){
        for(c=0;c<4;c++){
            if(jogo[l][c]>0){
                goto_xy(10+c*3,10+l*2);
                printf("%d",jogo[l][c]);
            }
        }
    }
}

Esta função utiliza a instrução goto_xy que não existe em C mas que está definida num header file que acompanha o código fonte do projeto.

Com as duas matrizes é fácil saber se o jogo foi resolvido, basta comparar as posições de uma matriz com a outra:

//terminou?!
int resolvido(void)
{
int l,c,r=1;
    for(l=0;l<4;l++){
        for(c=0;c<4;c++){
            if(solucao[l][c]!=jogo[l][c]) r=0;
        }
    }
    return r;
}

Como queremos que o computador resolva o jogo vamos utilizar uma tática simples, sempre que fizermos uma jogada guardamos o movimento realizado para mais tarde podermos reverter todos os movimentos até à posição inicial da matriz. Para isso vamos ter um vetor onde guardamos as jogadas e uma variável com o número de jogadas feitas.


int jogadas[100];
int n_jogadas;

Agora as funções que implementam as jogadas:


//move uma peça para a direita
void mover_direita(void)
{
int l,c;
int temp;

    pos_livre(c,l);
    if(coord_validas(c-1,l)==0) return;
    temp=jogo[l][c-1];
    jogo[l][c]=temp;
    jogo[l][c-1]=0;
    //guarda a jogada
    jogadas[n_jogadas]=DIREITA;
    n_jogadas++;
}
//move uma peça para a esquerda
void mover_esquerda(void)
{
int l,c;
int temp;

    pos_livre(c,l);
    if(coord_validas(c+1,l)==0) return;
    temp=jogo[l][c+1];
    jogo[l][c]=temp;
    jogo[l][c+1]=0;
    //guarda a jogada
    jogadas[n_jogadas]=ESQUERDA;
    n_jogadas++;
}
//move uma peça para cima
void mover_baixo(void)
{
int l,c;
int temp;

    pos_livre(c,l);
    if(coord_validas(c,l-1)==0) return;
    temp=jogo[l-1][c];
    jogo[l][c]=temp;
    jogo[l-1][c]=0;
    //guarda a jogada
    jogadas[n_jogadas]=BAIXO;
    n_jogadas++;
}
//move uma peça para baixo
void mover_cima(void)
{
int l,c;
int temp;

    pos_livre(c,l);
    if(coord_validas(c,l+1)==0) return;
    temp=jogo[l+1][c];
    jogo[l][c]=temp;
    jogo[l+1][c]=0;
    //guarda a jogada
    jogadas[n_jogadas]=CIMA;
    n_jogadas++;
}

Cada uma destas funções utiliza o seguinte algoritmo:
1. Descobrir as coordenadas do espaço livre na matriz (função pos_livre, apresentada a seguir)
2. Se as coordenadas do movimento não são válidas (função coord_validas, apresentada a seguir) não joga.
3. Guarda o número da peça a mover e troca com o 0 (zero) do espaço livre.
4. Guarda a jogada feita para mais tarde poder voltar atrás.
5. Adiciona um à variável n_jogadas.


//procura a posicao livre
void pos_livre(int &x,int &y)
{
int l,c;

    for(l=0;l<4;l++){
        for(c=0;c<4;c++){
            if(jogo[l][c]==0){
                x=c;
                y=l;
                return;
            }
        }
    }
}
//devolve 0 se as coordenadas estão fora da matriz
//devolve 1 se as coordenadas são válidas
int coord_validas(int x,int y)
{
    if(x<0 || y<0) return 0;
    if(x>3 || y>3) return 0;
    return 1;
}

Para terminar o programa faltam duas funções, uma para baralhar o puzzle e outra para resolver.
Aqui ficam:

//resolve o jogo
void resolver(void)
{
int n;

    for(n=n_jogadas-1;n>=0;n--){
        if(jogadas[n]==ESQUERDA) mover_direita();
        if(jogadas[n]==DIREITA) mover_esquerda();
        if(jogadas[n]==CIMA) mover_baixo();
        if(jogadas[n]==BAIXO) mover_cima();
        mostrar();
        Sleep(50);
    }
}
//baralha
void baralhar(void)
{
int movimento,temp,sorteia;
    srand(time(NULL));
    for(temp=0;temp<50;temp++){
        mostrar();
        Sleep(50);
        sorteia=rand()%4+1;
        switch(sorteia){
            case ESQUERDA :
                            mover_esquerda();
                            break;
            case DIREITA :
                            mover_direita();
                            break;
            case CIMA :
                            mover_cima();
                            break;
            case BAIXO :
                            mover_baixo();
                            break;
        }
    }
}

Esta versão da função baralhar mostra as jogadas ao mesmo tempo que baralha isso pode ser alterado removendo a linha que chama a função mostrar().

Agora para terminar de verdade aqui fica a função main:

int main(int argc,char *argv[])
{
char op;

    limpar();
    baralhar();
    while(1){
        mostrar();
        printf("\n\n\nOpcao (e,d,c,b,r):");
        scanf("%c",&op);
        if(op=='e') mover_esquerda();
        if(op=='d') mover_direita();
        if(op=='c') mover_cima();
        if(op=='b') mover_baixo();
        if(op=='r') resolver();
        if(resolvido()) break;
    }
    mostrar();
    system("pause");
    return 1;
}

Aqui chegados só falta jogar e quando não conseguir resolver o puzzle basta escolher r.

O código fonte.