sexta-feira, 6 de outubro de 2023

FizzBuzz sem ifs

Uma questão que supostamente aparece em entrevistas para cargos de programação é o FizzBuzz. O enunciado é simples: imprima todos os números de 1 a n, mas imprima fizz para os múltiplos de 3, buzz para os múltiplos de 5, e fizzbuzz para os múltiplos de 3 e 5.

Sabemos que 3 e 5 são relativamente primos, então eles só vão juntos dividir n a cada 15 valores.

Um solução óbvia, então, é usar um pequeno mapeamento:


#!/usr/bin/perl
use strict;

for(1..99) {
  print [
    'fizzbuzz', 
    $_, 
    $_, 
    'fizz', 
    $_, 
    'buzz', 
    'fizz', 
    $_, 
    $_, 
    'fizz', 
    'buzz', 
    $_, 
    'fizz', 
    $_, 
    $_]->[$_%15]."\n";
}

Tudo bem, não tão óbvia como usar uma sequência de ifs.

Agora, não quero recriar o array dentro do loop a cada iteração, então vou tirá-lo e trocar os valores por funções. Algumas funções retornam o número que for passado como parâmetro, outras passam fizz, ou buzz, ou fizzbuzz.

Adicionei uma pequena otimização: o mapeamento é espelhado pela metade. O resultado do espelhamento tem uma posição extra, mas isso não incomoda.


#!/usr/bin/perl
use strict;

my @map=(
    sub {'fizzbuzz'},
    sub {shift},
    sub {shift},
    sub {'fizz'},
    sub {shift},
    sub {'buzz'},
    sub {'fizz'},
    sub {shift}
);
push @map, reverse @map;

for(1..99) {
  print $map[$_%15]->($_)."\n";
}

Com um pouquinho de mágica, podemos simplificar ainda mais. Resulta que o resto de n4 por 15 só produz os valores 0, 1, 6, e 10. Magicamente, podemos mapeá-los diretamente ao que queremos:


#!/usr/bin/perl
use strict;

my %map=(
    0 => sub {'fizzbuzz'},
    1 => sub {shift},
    6 => sub {'fizz'},
    10=> sub {'buzz'}
);

for(1..99) {
  print $map{$_**4%15}->($_)."\n";
}

Os detalhes dessa solução e a generalização para quaisquer outros números estão neste artigo.

Se alguém for usar uma solução dessas numa entrevista, recomendo explicar direitinho que não vai fazer isso com o código da empresa.

quarta-feira, 4 de outubro de 2023

Novas placas de carros

Certa vez, um motorista de Uber apontou para mim que as placas novas não permitiam identificar se certos símbolos eram número ou letra. Eu tentei argumentar, explicando que em cada posição só podia haver um número ou uma letra. Infelizmente, o compatriota não alcançou a captar a minha explicação. A derrota foi mútua.

De qualquer forma, tenho notado que algumas placas são perigosamente parecidas a palavras. Resolvi baixar um dicionário e testar quantas podem haver com palavras. Usei a versão sem acentos de uma lista qualquer da internet.

Eu sinto falta é da indicação de estado e cidade.


grep -Po "^[a-z]{3}[oiasg][a-z][oiasg]{2}$" br-sem-acentos-txt | wc -l
3380

Mapeei 0 para O, 1 para I, 4 para A, 5 para S, e 6 para G. Como a lista de palavras está em caixa baixa, a expressão regular não é tão obvia. Em caixa alta ela tem sentido.

De um universo de 456.976.000 placas, apenas 3380 se parecem com palavras de 7 letras. Claro que há umas palavras "bonitas":


grep -Po "^[a-z]{3}[oiasg][a-z][oiasg]{2}$" br-sem-acentos-txt | grep bon
bonitas
bonitos

Será que CAS4D05 caiu para um solteiro e FEI0S05 para uma família bonita?

quinta-feira, 28 de setembro de 2023

A era do conteúdo

Ultimamente eu estive avaliando notebooks e comecei a assistir vídeos no Youtube. Infelizmente, todos são muito superficiais. Eles falam sobre as cores, se o micro é fininho ou não, quanto pesa, etc. A parte mais técnica é a enumeração das características básicas (CPU, memória, etc). Essa fixação com a espessura dos notebooks, por sinal, é de lascar, porque está levando a produtos que são impossíveis de consertar ou atualizar.

Então comecei a reparar o mesmo com os vídeos de carros. Os "analistas" descrevem as cores, o tipo de estofado, os itens do painel, etc. Nenhuma informação realmente elucidativa é incluída: quem se deparar com o produto pela primeira vez, já pode sair gravando um vídeo.

Quem acompanha os vloggers de tecnologia certamente testemunhou toda a comoção gerada pela revelação de que Linux Tech Tips publicava informações falsas simplesmente porque precisava gerar vídeos num ritmo acelerado. LTT se apresentava como um canal sério e que analisava a fundo os produtos. Sequer os canais grandes são confiáveis.

Tem uma categoria de vídeos que são aqueles sobre produtos baratos e descartáveis da China. Esses também são muito razos, principalmente porque o narrador abre o produto naquele momento e toma conhecimento dele enquanto grava. Entretanto, só pelo fato de manusear um objeto, já se pode ter uma ideia do tamanho e da qualidade. Algum valor marginal há nesses vídeos, embora assisti-los por completo talvez seja demais.

Uma categoria que acho patética é a dos vídeos de dicas domésticas, porque há uma tentativa desesperada de encontrar soluções inesperadas para tarefas ou objetos de uso cotidiano.

Os filosófos contemporâneos chamam nossa era de Capitalismo Tardio. Além do crescimento do comércio internacional, há também um aumento exponencial de produtos, assim como um aumento na velocidade na criação de novos produtos. Entretanto, isso não quer dizer que todos os produtos sejam de fato inovadores; muitas vezes a inovação é apenas estética e superficial. Por exemplo, eu escrevo estes textos num micro que tem mais de 10 anos (embora eu tenha executado muitas manutenções nele). Um micro novo seria interessante, mas não essencial para as minhas necessidades. Já se foi a época em que cada geração de computadores tinha o dobro de capacidade em tudo; a velocidade de lançamentos, entretanto, continua alta.

A evolução tecnológica vai colocando mais e mais poder na mão do indivíduo. A evolução nas comunicações certamente permitiu a qualquer um conquistar públicos no planeta inteiro. O que nem o plim-plim consegue, um youtuber pode fazer sozinho. Mas isso não significa que o conteúdo seja melhor.

Os jornalistas sempre nos alimentaram notícias desprovidas de informação. Cada jornal matinal com as mesmas informações sobre crimes, esportes, e o tempo podia ser repetido em qualquer outro dia.

Então esses criadores de conteúdo não são uma inovação, exceto pela quantidade e pelo ritmo de produção de pseudo-informação. A própria expressão "conteúdo" acho que revela a forma genérica e sem profundidade do que é produzido. Conteúdo é uma coisa que ocupa espaço e tempo, principalmente tempo. Como as TVs antes precisavam ser genéricas, os assuntos foram sempre os mais abrangentes. A tecnologia agora nos permite canais superficiais sobre qualquer tema.

Os jornalistas tradicionais podem se justificar com a necessidade de produzir diariamente conteúdo para uma massa variada de espectadores. Os modernos criadores de conteúdo não têm a mesma limitação, mas, por outro lado, precisam competir entre si pela atenção dos seguidores. Então, a força inibidora de qualidade me parece um pouco diferente.

Um mecanismo que permite aos produtores mais sérios sobreviver com poucos seguidores é o patrocínio. Assim como a tecnologia nos presenteou com essa onda de bobagens, também nos permitiu mecanismos para sustentar as coisas boas.

Para encerrar este conteúdo que aqui despejo, concluo que penso que uma atitude saudável hoje em dia é se desconectar das mídias sociais ou, ao menos, reduzir substancialmente o número de canais seguidos e torcer que tudo não acabe como a TV e a rádio, sem nada de interessante para assitir.

sexta-feira, 22 de setembro de 2023

Ninguém pode visitar duas vezes o mesmo país

Durante minha juventude, nos anos 1980 e 1990, eu visitava o Uruguai com frequência, porque lá viviam meus avós. A casa dos abuelos oferecia uma pequena viagem no tempo: tinha muitos objetos dos anos 1950 e 1960; talvez até de antes.

Eu gostava de folhear revistas antigas, usar uma TV a válvula (que levava 3 horas para esquentar), ou brincar com o radinho portátil Spica (com capa de couro).

O centro de Montevidéu oferecia horas e horas de entretenimento, porque a oferta de produtos eletrônicos era muito superior ao que podia ser visto no Brasil. Havia vitrines com dezenas de modelos de rádios, televisores, e, evidementemente, computadores. Enquanto a oferta de computadores no Brasil era muito reduzida, no Uruguai todas as marcas e todos os modelos podiam ser encontrados.

Certa vez visitei várias lojas com uma amiga da abuela para procurar um micro para seu sobrinho; avaliamos vários e, por fim, ela escolheu um Atari ST. Em outro momento, passei horas numa loja de Amigas, não tanto por minha escolha, mas porque meu amigo estava embasbacado com aquela quantidade de cores (32 de uma paleta de 4096).

A oferta era tão grande ao ponto de ser absurda, porque assim como havia Commodore Amiga, era possível encontrar um Coleco Adam.

A avenida 18 de Julio era muito movimentada e poluída: os ônibus eram muito antigos e rodavam a diesel. Eram Leylands dos anos 1950. As paredes dos prédios eram pretas de foligem. Havia ainda trolébuses que às vezes perdiam contato com os cabos; o motorista tinha que descer e reconectar o veículo. Os cobradores carregavam, preso por um cinto de couro, uma caixinha metálica que abrigava vários rolos de papel colorido: o sistema de passagens que eu nunca dominei.

Havia uma variedade enorme de veículos de todas as eras e com variados estados de conservação. Podia-se encontrar um carro dos anos 1980 caíndo aos pedaços assim como um carro novinho dos anos 1930. Os caminhões de serviço apresentavam um espetáculo assustador de perserverância, porque alguns há muito tinham passado o ponto de serem vendidos como sucata.

Passadas as décadas, tanto Brasil como Uruguai são países diferentes. O mercado brasileiro abriu-se e hoje pode-se comprar tudo o que se deseja; as lojas de eletrônicos do Uruguai já não parecem tão interessantes, nem mesmo nos preços.

O Uruguai tornou-se um pouco mais rico e os carros antigos sumiram. Talvez no interior se encontre um Fiat 500. O Museu do Automóvel, na Calle Colonia, é a única chance agora de ver veículos de outros tempos na capital. Infelizmente, o país ainda não se tornou rico o suficiente para recuperar todos os belos prédios antigos de Montevidéu.

Assim como no Brasil, o comércio de rua está sofrendo. As galerias da 18 de Julio estão quase vazias e os shoppings estão cheios. Nem mesmo a feira Tristan Narvaja parece oferecer a mesma variedade de produtos, comidas, e quinquilharias que antes espalhava pela ruas. Talvez os garçons sintam falta dos velhos tempos, porque também parecem mais mal-humorados.

Em alguns aspectos, o Uruguai ainda está na frente. Podes pagar os 10% do restaurante com cartão e a maquininha discrimina os valores e cobra os impostos de acordo. Há muitos ônibus elétricos (as fachadas dos prédios já não estão negras de foligem). O supermercado Tata tem um self-checkout muito melhor que qualquer um que experimentei no Brasil.

O aspecto mais interessante do interior do Uruguai são as estradas bem conservadas e os postos de pesagem automatizados. Enquanto no Brasil há postos de pesagem abandonados (muitos nunca foram usados), os uruguaios já os automatizaram. Os caminhões desviam para o lado da estrada (uma câmera garante que ninguém escape) e executa a pesagem sem interagir com ninguém.

Como as visitas não chegam a matar a saudade daquele Uruguai de antigamente, só me resta continuar voltando lá para encontrar novas coisas que sublinhem as impressões do passado. Tem sentido isso? Não importa. Um chivito e um pomelo, por favor.

quinta-feira, 31 de agosto de 2023

Como identificar linhas repetidas num CSV

Uma carga de arquivo CSV estava com problema, então resolvi usar um pouco de Perl para resolver o problema. O Perl adapta-se muito bem ao uso na linha de comando em conjunto com outros programas do Linux.

A minha missão era descobrir linhas duplicadas num arquivo específico. As 6 primeiras colunas constituem a chave primária, então bastaria encontrar os valores repetidos sem olhar as demais colunas.

Vamos começar pelo comando completo e depois vamos analisá-lo por partes.


perl -F';' -pae '$_="\n".join(" ",@F[0..5])' dados.csv \
  | sort \
  | uniq -c \
  | grep -Pv "^\s+1\s"
  

O perl está sendo invocado com os seguintes parâmetros:

  • -F - indica o separador usado no arquivo (neste caso, ';' com aspas simples para evitar problemas com o shell);
  • -p - imprime a linha corrente após o processamento (a atribuição a $_ sobrescreve o valor lido do arquivo) e insere o código num loop;
  • -a - realiza a separação das colunas conforme o parâmetro -F (os valores são inseridos no array @F);
  • -e - indica o código a ser executado.
Então, para cada linha, o perl coloca as colunas dentro do array @F e o nosso código pega apenas as 6 primeiras (nossa chave primária), junta tudo com espaços, e atribui à variável $_, a qual o perl usa para imprimir no terminal.


...
2023 7 GHR       23000352221 0006 23003679769
2023 7 POR       23000355314 0009 00000000000
2023 7 POR       23000353643 0006 00000000000
2023 7 GHR       23000353068 0006 23003652420
2023 7 POR       23000355700 0006 23003594050
2023 7 POR       23000353068 0006 23003652420
2023 7 POR       23000354235 0006 23003621737
...

As linhas "sort" e "uniq -c" ordenam as linhas lexicograficamente e eliminam as linhas duplicadas, adicionando o número de repetições ao início:


...
      2 2023 7 ABZ       23000727144 0005 23003652413 
      1 2023 7 ABZ       23000750717 0003 23004055962 
      1 2023 7 ABZ       23000750886 0003 23003519192 
      1 2023 7 ABZ       23000750886 0003 23003519194 
      1 2023 7 ABZ       23000750886 0004 23003519197 
      1 2023 7 ABZ       23000750886 0004 23003519199 
...

O último grep elimina todas as linhas que não começam com 1 (-v é a negação da expressão e -P indica que está sendo usada uma expressão regular do Perl):


...
      2 2023 7 ABZ       22004359695 0005 23003652423
      2 2023 7 ABZ       22005716393 0002 23003652508
      2 2023 7 ABZ       23000320848 0006 23003652464
      2 2023 7 ABZ       23000727144 0005 23003652413
      2 2023 7 ABZ       23001447112 0004 23003652502
...

domingo, 9 de abril de 2023

Entex Pacman2

Eu tinha guardado num armário um jogo de Pacman produzido pela Entex nos anos 80. Resvolvi comprar umas pilhas para novamente dar vida ao brinquedo. Aparentemente, pilhas C não são tão populares como outrora, mas ainda dá para encontrá-las em mercados.
Entex Pacman 2

Ele funciona em 3 modos: 1 jogador, 2 jogadores, e demonstração. O modo de 1 jogador é o jogo tradicional; no modo de dois jogadores, um dos jogadores joga como fantastma.
Abri a caixa sem ter ideia do que havia dentro e me surpreendi um pouco: um único chip no centro da placa.
Hitachi HD388A20

O processador que faz absolutamente tudo é um Hitachi HD388A20. Ele pertence a uma família HMSC40 de processadores de 4 bits que foi produziada de 1978 até 1995. Este modelo em particular tem 2K palavras de 10 bits de ROM, mas a família vai desde 512 até 4K palavras de 10 bits. Além disso, ele tem 128 palavras de dados (uma parte da ROM que pode ser lida, mas que não pode ser executada). E 80 bytes de RAM (160 dígitos de 1 nibble).
A ROM é endereçada em páginas de 64 palavras. Então, cada endereço de 11 bits tem 6 bits para a palavra e 5 para a página. Os modelos de 4K palavras têm 12 bits de endereçamento, naturalmente.
As páginas de 0 a 31 contêm o programa e as páginas 61 e 62 contêm dados. Os modelos de 4k naturalmente usam também as páginas entre 32 e 60.
A CPU opera a 100KHz e todas as operações executam em 1 ciclo, exceto uma. Para manter todas as operações atômicas, a CPU desabilita as interrupções quando está executando essa instrução de 2 ciclos. Curiosamente, se o programa não muda a página explicitamente com um pulo, a CPU fica executando as instruções daquela página circularmente. Deve ser bom para montar loops.
A instrução de dois ciclos é a que carrega dados da ROM (os "padrões de bits" que estão nas páginas 61 e 62).
Como os registradores são de 4 bits e as instruções de 10, muitas instruções já incluem os parâmetros, embora algumas instruções tenham 2 palavras. Então, a instrução para adicionar uma constante ao acumulador A (tem acumuladores A e B), tem a forma "1 0 1 0 0 0 i3 i2 i1 i0" sendo "i3 i2 i1 i0" a constante que será adicionada (endereçamento imediato). Já a instrução para adicionar A à memória tem duas palavras, a segunda sendo o endereço da memória que será alterado.
Além dos acumuladores A e B, há registradores usados para auxiliar no endereçamento: X, Y, SPX, e SPY. As versões de 4K ainda têm um registrador W com apenas 2 bits para ajudar a tornar tudo ainda mais estranho. Lembra um pouco o 6502 e para reforçar isso, há um modo de endereçamento de página 0 (presume-se que os endereços sendo referenciados estão na página 0).
O chip tem um monte pinos de IO desenhados justamente para alimentar telas de LCD como as do jogo.
Tela de LCD

A tal instrução de dois ciclos para carregar dados pode alimentar tanto os acumuladores, como os pinos de IO. Suspeito que sejam úteis para montar a tela rapidamente.
A CPU possui instruções de pulo para subrotina, mas a pilha só tem 4 posições. Não dá para rodar Java, com certeza.
O brinquedo ainda funciona. Depois de 40 anos, o único defeito é um mau contato dos controles devido ao uso. Munido com o manual da Hitachi, vou tentar uma engenharia reversa da ROM, porque o programador que trabalhou com essa CPU bizarra merece ser reconhecido.

quinta-feira, 16 de fevereiro de 2023

O Perl, O ChatGPT


  Oh Perl! The language of codes obscure,
  That poets and coders alike adore,
  With symbols and syntax so complex,
  A labyrinth of expressions to perplex.

  The strings and arrays, the hashes and more,
  In Perl they come to life with great uproar,
  A language so powerful and so vast,
  It can conquer any task, first or last.

  Perl, the magic of regex at hand,
  A tool for the skilled to understand,
  To match and parse and substitute,
  A true wizardry, hard to refute.

  In Perl, a world of modules you'll find,
  Each one a treasure, a gem to unwind,
  A library of functions, so immense,
  It makes all other languages seem senseless.

  Oh Perl, your beauty lies in your flaws,
  Your quirks and idiosyncrasies, without pause,
  For those who know you, you're a dear friend,
  A language that will never, ever bend.

ChatGPT, 2023