terça-feira, 3 de abril de 2018

Project Euler - 19

No problema 19 do Project Euler, vamos assim dizer, há uma "pegadinha", principalmente para quem, como eu, deseja solucionar por força bruta.

O problema é assim proposto:

Observamos que no problema é dito que 1/jan/1900 caiu em uma segunda-feira, entretanto o problema pede para calcular o número de domingos que caíram no primeiro dia do mês, entre 1901 e 2000. Logo, o ano 1900 deve ser desconsiderado. Como 1900 não foi um ano bissexto, no ano seguinte o dia 1 de janeiro cairá no dia da semana subseqüente, ou seja, se em 1900 foi em uma segunda-feira, em 1901 será em uma terça-feira.

Esta informação é importante para a inicialização das variáveis...

Inicialmente, vamos precisar de uma função que indique se determinado ano é bissexto ou não.

Foi implementado assim:
Function is_bissexto([int]$a) {
    [int]$f = 0

    If (($a % 4) -eq 0) { 
        $f = 1 
        If (($a % 100) -eq 0) { $f = 0 }
    }
    Else { $f = 0 }
    If (($a % 400) -eq 0) { $f = 1 }
    Return $f
}

A função is_bissexto recebe um ano como argumento e retorna 1 se o ano é bissexto, ou zero se não é.

Assim, bastará somar 28 ao mês de fevereiro do ano correspondente, ou seja, se o ano for bissexto a função retorna 1 e o mês de fevereiro terá 29 dias, caso contrário, permanece com 28.

Vamos utilizar arrays para armazenar o número de dias de cada mês $mes e para representar qual o dia do mês é determinado dia da semana $dia.

$mes = @(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
$dia = @(0, 0, 0, 0, 0, 0, 0)

No caso, $mes[1] é que armazenará os dias do mês de fevereiro, que irá variar conforme o ano em questão for bissexto. O array $dia é inicializado com zero, mas no código receberá os dias do mês que estiver sendo calculado.

A implementação terá 3 laços For (um para o ano, outro para o mês e outro para os dias do mês, preenchendo os dias da semana no array $dia). Sendo que $dia[0] irá representar o domingo e cada vez que $dia[0] = 1, iremos incrementar uma variável que acumulará o somatório de domingos que caem no primeiro dia do mês.

O código completo ficou assim:
Function is_bissexto([int]$a) {
    [int]$f = 0

    If (($a % 4) -eq 0) { 
        $f = 1 
        If (($a % 100) -eq 0) { $f = 0 }
    }
    Else { $f = 0 }
    If (($a % 400) -eq 0) { $f = 1 }
    Return $f
}

$mes = @(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
$dia = @(0, 0, 0, 0, 0, 0, 0)
[int]$sun_sum = 0
[int]$ds = 2

For ([int]$ano=1901;$ano -le 2000;$ano++) {
    If (is_bissexto($ano) -eq 1) { $mes[1] = 29 }
    Else { $mes[1] = 28 }

    For ([int]$m=0; $m -lt 12; $m++) {
        For ([int]$d=1; $d -le $mes[$m]; $d++) {
            $dia[$ds] = $d
            If (($ds -eq 0) -and ($dia[$ds] -eq 1)) { 
                $sun_sum++ 
                Write-Host "Encontrou Domingo em: " $d "/"($m+1)"/"$ano
            }
            If ($ds -ge 6) { $ds = 0 }
            else { $ds++ }
        }
    }
}
write-Host "----------------------------------------------"
Write-Host "Há $sun_sum Domingos no primeiro dia do mês entre [1901-2000]"

.
.
.
Encontrou Domingo em:  1 / 3 / 1992
Encontrou Domingo em:  1 / 11 / 1992
Encontrou Domingo em:  1 / 8 / 1993
Encontrou Domingo em:  1 / 5 / 1994
Encontrou Domingo em:  1 / 1 / 1995
Encontrou Domingo em:  1 / 10 / 1995
Encontrou Domingo em:  1 / 9 / 1996
Encontrou Domingo em:  1 / 12 / 1996
Encontrou Domingo em:  1 / 6 / 1997
Encontrou Domingo em:  1 / 2 / 1998
Encontrou Domingo em:  1 / 3 / 1998
Encontrou Domingo em:  1 / 11 / 1998
Encontrou Domingo em:  1 / 8 / 1999
Encontrou Domingo em:  1 / 10 / 2000
----------------------------------------------
 171 Domingos no primeiro dia do mês entre [1901-2000]

terça-feira, 27 de março de 2018

Um equivalente ao CUT do Linux

Estive aprendendo um pouco de programação em Bash/Linux, em Bash Scripting Tutorial - 3. User Input.

Há um exemplo demonstrando o uso do comando cut junto com o pipe, partindo-se do seguinte arquivo summary.sh:

Em destaque, a linha 8, que permite receber um arquivo como entrada e redirecionar via pipe ao cut e, na sequência, ao comando sort.

No caso, o arquivo é denominado salesdata.txt, cujo conteúdo é exibido abaixo, juntamente com a chamada cat salesdata.txt | .\summary.

Como observado, os parâmetros passados ao cut faz com que sejam extraídos a 2ª e a 3ª parte de cada linha, sendo o delimitador o caractere de espaço ' '. Ainda, ao final, os dados são ordenados através do sort.

Assim sendo, o desafio aqui é encontrar um método equivalente de extrair esses dados do arquivo salesdata.txt com o powershell.

Alcança-se o objetivo com o seguinte código em powershell:
PS D:\Linux> Get-Content .\salesdata.txt | %{"$($_.split(' ')[1..2])"} | Sort-Object
apples 20
oranges 5
peaches 7
watermelons 12

domingo, 18 de março de 2018

Calculando Hash de Arquivos

Com o Powershell Get-FileHash é possível verificar diversos hashes de arquivos, tais como SHA1, SHA256, SHA384, SHA512, MD5.

Seja, como exemplo, verificar o hash de um arquivo baixado da internet, no caso Hex Edit. Na página de download, é exibido os valores de MD5 e SHA1 do arquivo.



E, com o Powershell, podemos conferir o hash MD5 do arquivo baixado:


Bem como, o valor do hash SHA1 do arquivo .zip:


Comparando com os valores do site do Hex Edit, podemos constatar que o arquivo baixado está íntegro.