De volta à resolução de problemas

Resultado do Superprime Rib

Hoje, depois de umas férias de dois meses, resolvi um problema lógico do USACO Training Gateway: o Superprime Rib é um problema bem simples em que precisa-se determinar os primos de N dígitos (com N máximo = 8 ) que, tirando o último dígito, continuam sendo primos. A solução é trivial, uma função recursiva bastante simples que se auto-explica no meu código:

//Superprime Rib - USACO Training Gateway - 2005

/*
ID: contato1
PROG: sprime
LANG: C
*/

#include <stdio.h>
#define NMAX 9
#define INFINITO 100000

int primos[NMAX][INFINITO], cont[NMAX];

int eh_primo(long int num) {
	int i;

	if (num==1||(!(num%2)&&num!=2)) {
		return 0;
	}

	for (i=3; i*i<=num; i+=2) {
		if (!(num%i)) {
			return 0;
		}
	}

	return 1;
}

void funcao(int n) {
	int i, j, num;

	cont[n]=0;

	if (n>1) {
		funcao(n-1);

		for (i=0; i<cont[n-1]; i++) {
			for (j=1; j<=9; j+=2) {
				num=primos[n-1][i]*10+j;
				if (eh_primo(num)) {
					primos[n][cont[n]++]=num;
				}
			}
		}
	} else {
		primos[1][0]=2;
		primos[1][1]=3;
		primos[1][2]=5;
		primos[1][3]=7;
		cont[1]=4;
	}
}

int main() {
	int n, i;

	FILE *in=fopen("sprime.in", "r");
	FILE *out=fopen("sprime.out", "w");
	fscanf(in, "%d", &n);
	fclose(in);

	funcao(n);

	for (i=0; i<cont[n]; i++) {
		fprintf(out, "%d\n", primos[n][i]);
	}
	fclose(out);

	return 0;
}

O problema passou de segunda porque na primeira, por falta de hábito, eu tinha colocado scanf e printf ao invés de usar o sistema da USACO onde deve-se usar arquivos de entrada e saída.

Agora para eu ir para a seção 2 do USACO Training Gateway falta só o programa Checker Challenge, que parece ser complicado.

Instalei os pacotes do Slackware 10.2, que saiu essa semana, no laptop. Não tem nenhuma grande mudança, mas é sempre bom estar com os programas atualizados…

O Paulo Matias (Thotypous) me convidou para fazer parte da equipe de desenvolvimento da distro Guaranix, consertando alguns bugs do XDirectFB (que eu citei aqui). Acho que irei pegar um trabalho com a Meetweb também (o Hugo Dias, para quem eu fiz o serviço da Coalizão Antituberculose me convidou) e estou acabando o site do Colégio Salesiano, que é totalmente administrável em PHP e usa um banco de dados MySql. Ele deve sair semana que vem…

Dia 24 é a segunda fase da Olimpíada Regional de Matemática. Essa semana fiz a folhinha de treinamento e dos seis problemas, consegui fazer cinco (na verdade, alguns problemas - ou todos - eram repetidos do ano anterior e por isso fica mais fácil, porque eu já lembrava o caminho).

Only variables can be passed by reference

Instalei o PHP 5.0.5 no servidor do Colégio Salesiano na semana passada. E descobri que criaram um novo erro agora (do tipo fatal) para quando eu passo uma função como argumento de outra. “Fatal Error: Only variables can be passed by reference”. Bom… Uma função nada mais é que uma variável, afinal é pra isso que serve o seu retorno. Mas agora o PHP nos força, por exemplo, a fazer:

<?php
$variavel2=str_replace("a", "b", $variavel);
$variavel3=funcao($variavel2);
?>

… ao invés de fazer como eu sempre fiz para economizar linhas:

<?php
$variavel3=funcao(str_replace("a", "b", $variavel));
?>

Realmente não entendi o porquê da mudança. Pra mim tava muito bom do jeito anterior… E não sou só eu que faço isso. Os caras que fizeram o phpBB também passaram várias vezes funções como argumentos de outras e isso fez com que eu perdesse algum tempo hoje trocando todos as funções dessa maneira que mostrei acima no fórum do Colégio…

Alguém entende esses caras?

Escola, história, filosofia

Para não citar os fatos inúteis da escola (que são maioria), resolvi elogiar as aulas de história deste terceiro bimestre escrevendo neste artigo principalmente sobre filosofia. (e dessa vez não é só a do software livre!)

Pitágoras

Nesse ano, voltamos a ter aulas de história de verdade, com uma professora de verdade e conteúdo de verdade. Quem conheceu o antigo professor Roberto, sabe do que eu estou falando… ;) Bom… Desde o começo do ano, estou gostando bastante de história. É uma matéria bem interessante que sempre nos faz pensar bastante e usar a lógica (aliás, a lógica lembra a razão, a Aristóteles e aos filósofos gregos). Não tá dando pra usar muito a lógica nas aulas de matemática, pois o professor se limita a ensinar PA, PG, funções de segundo grau e essas babaquices apenas usando fórmulas prontas. Sei que não é sua culpa, existe gente com sérias dificuldades de entendimento, mas acho que a escola muitas vezes é um repetir de fórmulas e exercícios que não ajudam a desenvolver o raciocínio. Então eu acho incrível que neste sentido, as aulas de história estão sendo as melhores deste ano.

Nesse bimestre, a professora Fabiana nos passou um trabalho sobre os filósofos gregos. O meu grupo falou sobre o filósofo Pitágoras, aquele que via números em tudo (e, sim, aquele mesmo que criou o Teorema) e aí comecei a ver uma relação (um pouco estranha) entre a matemática, a lógica, a razão, a filosofia e a história. E já que filosofia é amar a sabedoria, fica mais fácil entender toda essa relação, porque sabedoria é matemática… :D

O Mundo de Sofia

Bom… Agora estou relendo “O Mundo de Sofia”, desta vez lendo e relendo com atenção até as cartas de dezenas de páginas às vezes um pouco complicadas sobre a história de vários filósofos. E fica aí a sugestão desse excelente livro (é interessante as histórias que o autor conta, que deixam coisas complicadas bem mais simples, como entender a filosofia de Demócrito como o brinquedo Lego).

Ahnnn… E acho que esse post foi só pra falar disso mesmo, só para não concluir nada, mas só dizer como vai a escola e que ainda tem alguma coisa para se aprender lá, uma coisa pra fazer pensar lá. :) E, aliás, ainda não tô concluindo nada, só tô vendo as idéias dos filósofos “famosos” e refletindo sobre elas…

Agora em História, continuamos estudando a Grécia, e agora partindo para os etruscos para chegar em Roma, mas fica registrada aqui a minha felicidade por estar tendo a oportunidade de pensar (usando o raciocínio lógico) mesmo nesta disciplina.


Agora mudando radicalmente de assunto para dizer as últimas novidades, além da filosofia…

O beta do Firefox 1.5 saiu, já estou utilizando-o como padrão… Achei ele igual o meu outro Deerpark Alpha (a.k.a. Firefox 1.6a1) Já que no outro post já comentei sobre suas vantagens, pararei por aqui.

Olimpíada Regional de Matemática

A segunda fase da Olimpíada Regional de Matemática (catarinense) acontecerá no dia 24 deste mês e ainda não aprendi nada de novo sem ser filosofia, desde meu péssimo resultado na segunda fase da OBM.

A política no Brasil tá triste, não vejo escolhas sem mudar o sistema político, acabar com o capitalismo e com essa história de querer lucrar em tudo. Mas já que eu também sou um capitalista e nunca estudei direito sobre isso, e já tenho problemas menores suficientes para me incomodar, fica registrada aqui a tristeza mas o conformismo com essa situação. Na realidade, não sei quem não sabia ainda que os políticos brasileiros eram corruptos, mas agora é uma crise mais séria, tá tudo estourando… Não sei o que podemos fazer pra ajudar!

Fiz grandes alterações no meu site… Mudei a organização de todos os links, as regras do módulo ReWrite, adicionei feed do Flickr e criei um sitemap em XML do Google, mudei os permalinks dos artigos, as cores dos comentários, adicionei referências (permalinks) aos comentários… Um monte de coisa! :blink: E ainda tô querendo mexer em outras coisas… ;)

Tô testando uns sistemas de wiki para meu projeto de software livre para leigos, não tô conseguindo achar nada muito legal em PHP. Aquele “PHPWiki” não funciona direito, tive que modificar um monte de coisas e ainda assim apresentou problemas e tô quase decidindo fazer um eu mesmo.

Depois de um muito tempo, joguei RPG novamente este sábado… É meio esquisito interpretar um personagem na Idade Média, já é tão esquisito interpretar nós mesmos! :blink:

O site do Colégio tá quase pronto, estou precisando da biblioteca GD para trabalhar com redimensionamento de imagens e outras coisas com imagens no PHP e o cara que cuida do servidor FreeBSD ficou de instalar para mim, mas ainda não o fez… (gostaria tanto que fosse um Linux que eu mesmo tivesse configurado!)

Richard Stallman

Estou tentando fazer um Linux simples e acessível para minha família usar no computador que compartilha internet com o meu laptop, mas ainda não consegui nem instalar Linux (eu vivo instalando e desinstalando Linux aqui do lado… Esses caras não entendem como Linux é bom, a filosofia é linda e devemos parar de usar MSN e programas da Microsoft!). A mesma coisa eu quero fazer no Colégio depois que acabar de fazer o site. O Laboratório de Informática deveria ser só Linux. O KDE tem programas educativos tão legais, fora outros que podemos achar na internet… E tem programas para Ensino Médio que o nosso Lab. nem tem nem semelhantes. O problema é que ele tem uma grande quantidade de programas para a pré-escola e acho difícil encontrar bons clones para Linux. Eu acho que instalar Linux na escola é uma coisa indispensável e não pretendo sair de lá antes que esta missão esteja cumprida. Quero fazer ainda um esquema bem legal com um servidor e clientes usando NFS/NIS e com os clientes loggando no servidor e facilitando a vida da profa. de informática.

Fiz uma alteração nas Funções ZZ adicionando uma senha ao zzss (proteção de tela para console). O patch está disponível aqui no meu servidor: patch.zz (esse patch foi perdido pelo tempo) e para patchar basta usar patch -p1 apontando para ele o arquivo do patch (patch.zz) e colocar no File to patch a localização do seu arquivo funcoeszz (tem que ser a última versão).

Para finalizar, não tenho produzido muitos códigos / solucionado problemas lógicos, mas tenho pensado bastante logicamente e até ando vendo alguns grafos no pensamento e criando quase inconscientemente uns algoritmos… Embora não esteja implementando ou escrevendo os algoritmos, acho que estou desenvolvendo-os… Hehehe… (parece que eu sou louco, né?)

Coloquei várias imagens aí em cima pro post não ficar muito sem graça, já que ficou um pouco grande… A maioria delas não é tão importante, mas são boas pra saber em que pedaço do texto estamos… :)

Feed RSS, Google e OBM

Finalmente implementei o feed RSS que estava faltando na minha página… O Gustavo Custódio, do Colégio, me lembrou de criá-lo e fiz isso agora a noite mesmo…

Segui o padrão do Bruno Torres, porque não tenho muita experiência com feeds XML/RSS e criei até um XSL para não ficar só o feed mesmo, mas ter um “estilo associado a ele”, como diz o Mozilla.

Hmmm… Então agora vocês já podem ver o conteúdo do site via os feeds (o que facilita bastante)… E aproveitem para se encontrarem algum erro (eu fiz na pressa) me avisarem. :)

Hoje coloquei também em minha página o programa Google Adsense. Coloquei um pequeno banner (de 468×60) localizado embaixo do primeiro post da página e outro no rodapé da página e acho que não poluiu e aliás, as cores ficaram discretas e bonitas. :D (hehehe, sou o primeiro cara que diz que gosta de ads no mundo!).

E por falar em Google, nessa semana testei vários serviços deles. Começou com o GoogleTalk e depois que meu irmão colocou rótulo pra “todos” os lugares do mundo no GoogleEarth acabamos realmente nos viciando em Google. Mas os serviços deles são ótimos!

Boatos dizem que o Google vai dominar o mundo e o Pink e o Cérebro trabalham lá. Não sei se é verdade, mas cada vez mais acho que isso realmente faria sentido! Hehehe…

Sábado é a segunda fase da OBM (Olimpíada Brasileira de Matemática) e também começa o Festival de Música de Itajaí. Na Olimpíada, acho que não tenho muita chance e, aliás, nessa semana também andei estudando um pouco (com o César Kawakami inclusive, que me passou umas coisas bem legais sobre Teoria dos Números). No festival, me inscrevi para fazer piano mesmo com o Michel Friedenson.

Depois da semana do festival de música, quero voltar a programar logicamente. Essa semana só tentei fazer coisas em GTK, mas sem muito sucesso (aprendi um pouco de C/GTK, mas depois resolvi PHP/GTK porque PHP é uma linguagem mais completa, mas ainda não decidi nada)…

Estatísticas de Visita com Shortstat

Comecei a usar o Shortstat para acompanhar as estatísticas do site. Porém, tive alguns problemas com ele (não exatamente problemas, mas coisas que eu acho melhor mudar). Exemplos:

  • As estatísticas de browser e sistema são contadas por hit… Eu acho muito mais sensato contar por visita (única), pois algumas pessoas contam vários hits (exemplo: eu) e daí as minhas estatísticas estavam dizendo que 80% dos visitantes usavam Linux!
  • Os webcrawlers e alguns browsers são registrados como sistema operacional desconhecido

Já que o sistema é feito em PHP, achei legal consertar estes problemas e até traduzir e colocar uma bandeira do lado dos países. emoticon Vou postar aqui um passo-a-passo de instalação e esas configuração do Shortstat para quem precisar. Achei ele um ótimo sistema de estatísticas (código super simples e bem direto) e tem tudo que eu preciso. :)

Introdução

O Shortstat é um programa de estatísticas da ShaunInman escrito em PHP que usa um banco de dados MySql para incluir os registros. O funcionamento é bastante simples. Em cada página, eu uso um include para um arquivo que conta visita e existe um arquivo que conta as estatísticas. Estou partindo do princípio que você já tem PHP e MySql configurados num servidor web.

Download

O download do programa .zip pode ser feito aqui:

http://www.shauninman.com/downloads/shortstat_v036b.zip

No Linux, use o comando unzip shortstat_v036b.zip para descompactar.

No Windows, use um programa como WinZip ou WinRar (ou o descompactador do Windows XP).

Arquivos Descompactados

  • configuration.php – Configuração do banco de dados
  • functions.php – Funções do programa (toda a parte de PHP)
  • inc.stats.php – Arquivo que deve ser incluído em cada página do site pra contar visita
  • index.php – Página onde se vê as estatísticas
  • styles.css – Estilos (css) da página index.php

E ainda tem os arquivos de instalação (que poderão ser deletados logo que acabar a instalação).

IP dos Países

O Shortstat vem com um arquivo de 2mb (_ip-to-country.txt) que tem um banco de dados com ip de vários países e outro php (_ip-to-country.php) que serve para instalar o suporte ao “ip-to-country”. Depois de instalar o Shortstat normal, nós vamos instalar também para saber de onde são os visitanets do site.

Instalação

Para instalar o Shortstat, edite o arquivo configuration.php colocando nas variáveis:

<?php
$SI_db['server']="servidor_do_mysql";
$SI_db['username']="username_do_mysql";
$SI_db['password']="senha_do_mysql";
$SI_db['database']="nome_do_banco_de_dados";
$tz_offset=seu_fuso_horario;
$shortstat=true;
?>

E rode o script de instalação (_install.php) no seu browser. Ele irá criar as tabelas no seu banco de dados. Daí basta acrescentar:

<?php @include_once("diretorio_do_shortstat/inc.stats.php"); ?>

… no início de cada arquivo que você quer que sejam contadas as estatísticas.

Antes de instalar o ip-to-country, eu criei uma coluna chamada codigopais no banco de dados MySql e modifiquei o arquivo functions.php criando uma função chamada verCodigoPais:

<?php
function verCodigoPais($ip) {
       if (!SI_isIPtoCountryInstalled()) return '';
       global $SI_tables;
       $ip = sprintf("%u",ip2long($ip));

       $query="SELECT country_code2 AS codigo FROM $SI_tables[countries] WHERE ip_from <= $ip AND ip_to >= $ip";
       if ($result=mysql_query($query)) {
              if ($r = mysql_fetch_array($result)) {
                     return $r['codigo'];
              }
       }
}
?>

No arquivo inc.stats.php, depois de atribuir um valor para a variável $ip, coloquei:

<?php
$cd     = verCodigoPais($ip);
?>

… e depois de colocar valor em todas as variáveis alterei a $query para:

<?php
$query = "INSERT INTO $SI_tables[stats] (remote_ip, country, codigopais,
domain, referer, resource, user_agent, platform, browser, version, dt)
VALUES ('$ip', '$cntry', '$cd', '$domain', '$ref', '$res', '$ua', '$br[platform]',
'$br[browser]', '$br[version]', $dt)";
?>

(a única mudança foi a adição da variável cd – que contém o código do país – no campo codigopais do banco de dados)

Agora basta imprimir a bandeira do país… Para isso, no arquivo functions.php alterei a função SI_getCountries:

<?php
function SI_getCountries() {
       global $SI_tables,$_SERVER;

       $query = "SELECT country, codigopais, COUNT(distinct(remote_ip)) AS 'total'
                       FROM $SI_tables[stats]
                       WHERE country!=''
                       GROUP BY country
                       ORDER BY total DESC";

       if ($result = mysql_query($query)) {
              $ul  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t

<tr>
  <th>
    Country
  </th>

  <th class="last">
    Visits
  </th>
</tr>n";
              $i=0;
              while ($r = mysql_fetch_array($result)) {
                     if ($i < 36) {
                            $url = parse_url($r[referer]);
                            $ul .= "t

<tr>
  <td>
    <img src="http://ip-to-country.webhosting.info/flag/?type=3&cc2=$r[codigopais]" alt="$r[codigopais]" /> $r[country]
  </td>

  <td class="last">
    $r[total]
  </td>
</tr>n";
                            $i++;
                            }
                     }
              $ul .= "</table>";
              }
       return $ul;
}
?>

(note que a imagem é buscada direto do servidor do ip-to-country)

Então, agora é só instalar o ip-to-country, mas o arquivo de instalação só está servindo para colocar o nome do país no banco de dados (não o código). Basta modificar o arquivo _ip-to-country.php, alterando:

<?php
echo "<p>Mapping existing IPs to countries.</p>";
// Match existing ips to countries
$query = "SELECT id,remote_ip FROM $SI_tables[stats] WHERE country=''";
if ($result = mysql_query($query)) {
   while ($r = mysql_fetch_array($result)) {
      $country = SI_determineCountry($r[remote_ip]);
      $query = "UPDATE $SI_tables[stats] SET country='$country' WHERE id=$r[id]";
      mysql_query($query);
   }
}
?>

… para…

<?php
echo "<p>Mapping existing IPs to countries.</p>";
// Match existing ips to countries
$query = "SELECT id,remote_ip FROM $SI_tables[stats] WHERE country=''";
if ($result = mysql_query($query)) {
   while ($r = mysql_fetch_array($result)) {
      $country = SI_determineCountry($r[remote_ip]);
      $cd = verCodigoPais($r[remote_ip]);
      $query = "UPDATE $SI_tables[stats] SET country='$country' AND codigopais='$cd' WHERE id=$r[id]";
      mysql_query($query);
   }
}
?>

Daí é só rodar o arquivo _ip-to-country.php e o ip-to-country estará funcionando junto com o shortstat com bandeira do lado do país! :)

Estatísticas por visitas, não por hits

Eu alterei a função SI_getPlatforms por:

<?php
function SI_getPlatforms() {
       global $SI_tables;
       $th = SI_getUniqueHits();
       $query = "SELECT platform, COUNT(distinct(remote_ip)) AS 'total'
                       FROM $SI_tables[stats]
                       GROUP BY platform
                       ORDER BY total DESC";
       if ($result = mysql_query($query)) {
              $ul  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t

<tr>
  <th>
    Platform
  </th>

  <th class="last">
    %
  </th>
</tr>n";
              while ($r = mysql_fetch_array($result)) {
                     $ul .= "t

<tr>
  <td>
    $r[platform]
  </td>

  <td class="last">
    ".number_format(($r[total]/$th)*100)."%
  </td>
</tr>n";
                     }
              $ul .= "</table>";
              }
       return $ul;
}
?>

A mudança foi o count usar distinct(remoteip) e o $th ter o valor dos hits únicos (daí a porcentagem é contada a partir deles). A mudança na função **SIgetBrowsers** é semelhante:

<?php
function SI_getBrowsers() {
       global $SI_tables;
       $th = SI_getUniqueHits();
       $query = "SELECT browser, version, COUNT(distinct(remote_ip)) AS 'total'
                       FROM $SI_tables[stats]
                       WHERE browser != 'Indeterminable'
                       GROUP BY browser, version
                       ORDER BY total DESC";
       if ($result = mysql_query($query)) {
              $ul  = "<table cellpadding="0" cellspacing="0" border="0">n";
              $ul .= "t

<tr>
  <th>
    Browser
  </th>

  <th>
    Version
  </th>

  <th class="last">
    %
  </th>
</tr>n";
              while ($r = mysql_fetch_array($result)) {
                     $p = number_format(($r[total]/$th)*100);
                     // $p = ($p==0)?"<1":$p;
                     if ($p>=1) {
                            $ul .= "t

<tr>
  <td>
    $r[browser]
  </td>

  <td>
    $r[version]
  </td>

  <td class="last">
    $p%
  </td>
</tr>n";
                            }
                     }
              $ul .= "</table>";
              }
       return $ul;
}
?>

Conclusão

Assim temos um Shortstat configurado para as minhas necessidades. Eu gosto assim, mas por ser um sistema de código bastante simples em PHP você pode configurar mais o que quiser. Eu traduzi (é só modificar as coisas no index.php) também (não tem uma grande utilidade, mas não custa…)

Espero que tenham gostado do “artigo” e qualquer dúvida ou crítica, postem um comentário ou enviem um e-mail.

© 2005–2020 Tiago Madeira