<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Caio Lente</title>
    <link>https://lente.dev/</link>
    <description>Recent content on Caio Lente</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>pt-BR</language>
    <managingEditor>c@lente.dev (Caio Lente)</managingEditor>
    <webMaster>c@lente.dev (Caio Lente)</webMaster>
    <copyright>Caio Lente (CC BY 4.0)</copyright>
    <lastBuildDate>Tue, 17 Jan 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://lente.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Pipelines de Amplificação</title>
      <link></link>
      <pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>R para Ciência de Dados III</title>
      <link></link>
      <pubDate>Sun, 18 Jun 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>R para Ciência de Dados II</title>
      <link></link>
      <pubDate>Mon, 24 Apr 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Submódulos no Git</title>
      <link>https://lente.dev/posts/submodulos-git/</link>
      <pubDate>Sat, 15 Apr 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/submodulos-git/</guid>
      <description>Um pequeno tutorial para quem quer começar a usar submódulos no Git</description>
      <content:encoded><![CDATA[<p>Ano passado, o time da <a href="https://curso-r.com/">Curso-R</a> se reuniu para conversar
sobre a nova estrutura dos nossos <a href="https://loja.curso-r.com/">cursos</a>. Um dos
pontos da pauta era a organização dos nossos repositórios que, ao longo dos
anos, foi ficando cada vez mais difícil de manter.</p>
<p>Cada oferecimento de cada curso tem um repositório no
<a href="https://github.com/curso-r">GitHub</a>, o que nos permite personalizar o conteúdo
de uma turma sem afetar as outras. Mas essa granularidade cria um problema: o
que fazer com o material que é comum a todas as turmas de um mesmo curso?</p>
<h2 id="o-problema">O problema</h2>
<p>Imagine que existe uma <strong>turma A</strong>, que participou do curso <a href="https://loja.curso-r.com/r-para-ciencia-de-dados-3.html"><em>R para Ciência de
Dados III</em></a> este ano, e
uma <strong>turma B</strong>, que vai fazer o curso no ano que vem.</p>
<p>No passado nós copiávamos todo o conteúdo do repo A para o repo B, mas hoje em
dia nós criamos os repositórios dos cursos com antecedência. Isso significa que
qualquer alteração no material durante o oferecimento A precisaria ser propagada
cuidadosamente para para o oferecimento B; infelizmente isso pode dar muito
trabalho.</p>
<p>A solução que encontramos foi criar um repositório <code>main</code> para cada curso, ou
seja, um repo central que contém apenas os slides. Assim, os repos das turmas só
precisam hospedar o conteúdo que muda de um oferecimento para o outro
(exercícios, anexos, comentários, etc.) e qualquer alteração nos slides
imediatamente se aplica a todos os repos satélites.</p>
<p>Tudo funcionou perfeitamente bem até que decidimos fazer a primeira mudança na
<em>ementa</em> de um curso. O problema desta estratégia é qualquer alteração no <code>main</code>
é propagada para o passado; logo, se durante o oferecimento B resolvermos fazer
uma reestruturação grande no material, a turma A vai perder a versão dela e
ficará sem as suas referências.</p>
<p>O ideal seria ter uma maneira de atualizar os slides seletivamente, ou seja,
manter a turma A na versão anterior do <code>main</code> e passar a B para a versão nova.
Isso tudo sem quebrar os repos feitos com antecedência.</p>
<h2 id="submódulos">Submódulos</h2>
<p>É aí que entram os submódulos. De acordo com a
<a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">documentação</a>, eles são
essencialmente repos dentro de outros repos, ou seja, clonamos um repo (o
submódulo) dentro de um repo hospedeiro. Inception.</p>
<p>Como eu posso usar submódulos para resolver meu problema com as turmas? Eu posso
continuar usando o repo <code>main</code> para armazenar os slides, mas, ao invés de
deixá-lo isolado, ele seria clonado como submódulo dentro do repo de cada turma.
Neste arranjo, eu posso apontar o submódulo da turma A para a versão antiga do
<code>main</code> e manter o da turma B apontado para a versão mais nova.</p>
<p>Para começar a usar submódulos, eu recomendo executar os seguintes comandos Git,
pois eles garantem que o seu ambiente estará adequadamente preparado:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git config --global submodule.recurse <span class="nb">true</span>
</span></span><span class="line"><span class="cl">git config --global push.recurseSubmodules check</span></span></code></pre></div><p>Agora, dentro do repositório desejado, eu posso rodar o comando abaixo para
trazer o repo <code>main</code> como um submódulo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git submodule add https://github.com/curso-r/main-r4ds-3.git materiais/</span></span></code></pre></div><p>Isso é muito similar a fazer um clone normal! No caso, o repositório
<code>main-r4ds-3</code> será clonado na pasta <code>materiais/</code> no repo hospedeiro.</p>
<p>A partir de agora, eu posso usar sempre o repo hospedeiro, sem me preocupar com
o <code>main</code>. Se eu fizer uma alteração na pasta <code>materiais/</code>, basta fazer um commit
como qualquer outro! A atualização não vai para o repo da turma, mas sim para o
<code>main</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> materiais/
</span></span><span class="line"><span class="cl">git add -A
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;Alteração no main&#34;</span>
</span></span><span class="line"><span class="cl">git push</span></span></code></pre></div><p>Se voltarmos para a pasta um nível acima e executarmos <code>git status</code>, vamos ver
que houve uma alteração em um arquivo chamado <code>.gitmodules</code>. Isso quer dizer que
o submódulo foi atualizado no GitHub, não que ele foi atualizado no repo da
turma.</p>
<p>Este é o pulo do gato: podemos atualizar o <code>main</code> quantas vezes quisermos, mas
as atualizações só serão propagadas para o repo da turma se aceitarmos a
alteração.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> ../
</span></span><span class="line"><span class="cl">git status
</span></span><span class="line"><span class="cl">git add -A
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;Aceitando alterações do main&#34;</span>
</span></span><span class="line"><span class="cl">git push</span></span></code></pre></div><p>Isso permite que o repo de uma turma antiga como a A mantenha a sua referência a
uma versão anterior do <code>main</code> ao mesmo passo que o repo das turmas novas podem
ter suas referências atualizadas com facilidade. Se você quiser um exemplo de
como fica uma referência no GitHub, dê uma olhada na demo de submódulos que
fizemos na Curso-R:
<a href="https://github.com/curso-r/202211-demo-submod">https://github.com/curso-r/202211-demo-submod</a>.</p>
<p>E isso é tudo. Se você quiser uma demonstração em vídeo, a referência que eu
usei foi <a href="https://www.youtube.com/watch?v=gSlXo2iLBro">essa aqui</a> do Redhwan
Nacef. Se você tiver qualquer dúvida, mande um email para mim e eu vou tentar
ajudar o máximo possível. Até a próxima!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Indexando listas no R</title>
      <link>https://lente.dev/posts/indexando-listas/</link>
      <pubDate>Fri, 14 Apr 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/indexando-listas/</guid>
      <description>Vamos aprender de uma vez por todas a indexar listas no R</description>
      <content:encoded><![CDATA[<p>Uma peculiaridade do R que assusta muita gente é a indexação de listas.
Indexar vetores é simples, basta usar a sintaxe <code>vetor[i]</code>, onde <code>i</code> é o
número do elemento que você quer, mas as listas têm o problema do
colchete duplo: <code>lista[[i]]</code>. Qual é a diferença entre os dois? Vamos
tentar entender de uma vez por todas.</p>
<h2 id="introdução">Introdução</h2>
<p>Se você não sabe o que é uma lista, o conceito é na verdade bastante
simples: elas funcionam como vetores, mas aceitam objetos de vários
tipos (incluindo sub-listas). Abaixo estou criando uma lista <code>l</code> e
exibindo a sua estrutura com a função <code>str()</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">objeto</span> <span class="o">=</span> <span class="s">&#34;abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">vetor</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">lista</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="kc">TRUE</span><span class="p">,</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">str</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; List of 3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  $ objeto: chr &#34;abc&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  $ vetor : num [1:3] 1 2 3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  $ lista :List of 2</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   ..$ : logi TRUE</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   ..$ : logi FALSE</span></span></span></code></pre></div><p>Repare em algumas propriedades das listas:</p>
<ol>
<li>
<p>Podemos nomear os seus elementos, mas também podemos deixá-los sem
nome nenhum. Isso também é possível com vetores, mas por algum
motivo é mais comum ver listas nomeadas.</p>
</li>
<li>
<p>Diferentemente de vetores, podemos colocar elementos de qualquer
comprimento dentro de uma lista.</p>
</li>
<li>
<p>Uma lista pode ter sub-listas (e sub-sub-listas, sub-sub-sub-listas,
etc.) Isso não afeta em nada o seu comportamento, mas vamos precisar
aprender a fazer indexações profundas.</p>
</li>
</ol>
<h2 id="indexação">Indexação</h2>
<p>Acessar elementos de listas é um pouco mais complicado do que vetores. A
base é a mesma: <code>[i]</code> retorna a <code>i</code>-ésima posição. O problema é que, nas
listas, existe uma diferença entre a <strong>posição</strong> de um elemento e o
<strong>elemento</strong> em si.</p>
<p>A <code>i</code>-ésima posição, em uma lista, sempre é uma lista. Para pegar o
<code>i</code>-ésimo elemento, precisamos usar <code>[[i]]</code>! Alternativamente, em listas
nomeadas, podemos usar <code>[&quot;nome&quot;]</code> e <code>[[&quot;nome&quot;]]</code> (equivalente a
<code>$nome</code>).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[1]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; $objeto</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;abc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">l[[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;abc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">l[</span><span class="s">&#34;objeto&#34;</span><span class="n">]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; $objeto</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;abc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;objeto&#34;</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;abc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">objeto</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;abc&#34;</span></span></span></code></pre></div><p>É aqui que começa o nosso problema. É conceitualmente difícil de
entender a diferença entre uma posição e um elemento, ou seja, quando
usar <code>[]</code> e quando usar <code>[[]]</code>. Para tentar ilustrar melhor, vamos usar
a metáfora da rua.</p>
<h2 id="metáfora-da-rua">Metáfora da rua</h2>
<p>Vamos pensar em listas como ruas. Quando usarmos <code>[]</code> obteremos um
trecho da rua e quando usarmos <code>[[]]</code> obteremos a família da casa
correspondente. Seguindo a lógica da metáfora, um elemento-vetor é uma
casa com vários moradores e um elemento-lista é uma vila que pode ter
várias casas dentro.</p>
<figure><img src="https://lente.dev/posts/indexing-lists/l.webp"/>
</figure>
<p>Se quisermos pegar o trecho da rua que contém a primeira casa, podemos
usar <code>[i]</code> ou <code>[&quot;nome&quot;]</code>. Ambos funcionam igual:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[1]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[</span><span class="s">&#34;objeto&#34;</span><span class="n">]</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B1%5D.webp"/>
</figure>
<p>Quando estamos falando de trechos da rua (segmentos da lista), podemos
fazer seleções maiores. Abaixo, por exemplo, estamos selecionando as 2
últimas casas ou, alternativamente, todas as casas menos a primeira.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[2</span><span class="o">:</span><span class="m">3</span><span class="n">]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="nf">[c</span><span class="p">(</span><span class="s">&#34;vetor&#34;</span><span class="p">,</span> <span class="s">&#34;lista&#34;</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[</span><span class="m">-1</span><span class="n">]</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B-1%5D.webp"/>
</figure>
<p>Se quisermos selecionar os integrantes de uma casa (um elemento da
lista), aí precisamos usar <code>[[i]]</code>, <code>[[&quot;nome&quot;]]</code> ou <code>$nome</code>. Note que a
última opção é igual à seleção de colunas em um data frame.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[[1]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;objeto&#34;</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">objeto</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B%5B1%5D%5D.webp"/>
</figure>
<p>O processo para selecionar a família da casa 2 é idêntico, não importa
que a casa 2 contém um vetor e a casa 1 contém um objeto simples.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[[2]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;vetor&#34;</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">vetor</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B%5B2%5D%5D.webp"/>
</figure>
<p>Idem para a casa 3, ou seja, a vila da nossa rua. O endereço é um só,
mas dentro deste endereço temos uma nova casa 1 e uma nova casa 2.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[[3]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;lista&#34;</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">lista</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B%5B3%5D%5D.webp"/>
</figure>
<p>Se quisermos acessar a casa 1 da vila, podemos fazer indexação profunda.
Para isso, basta colocar no final da nossa expressão mais um <code>[1]</code>!
Funcionaria exatamente igual se nós quiséssemos pegar o primeiro
elemento do vetor <code>l$vetor</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[[3]][1]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;lista&#34;</span><span class="n">]][1]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">lista[1]</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B%5B3%5D%5D%5B1%5D.webp"/>
</figure>
<p>Por fim, se quisermos pegar os integrantes da casa 1 da vila, basta
adicionar um <code>[[1]]</code> na nossa indexação da vila analogamente ao que
fizemos acima. No limite, não importa quantas sub-listas você tem, basta
adicionar mais colchetes duplos conforme a necessidade.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">l[[3]][[1]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l[[</span><span class="s">&#34;lista&#34;</span><span class="n">]][[1]]</span>
</span></span><span class="line"><span class="cl"><span class="n">l</span><span class="o">$</span><span class="n">lista[[1]]</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/indexing-lists/l%5B%5B3%5D%5D%5B%5B1%5D%5D.webp"/>
</figure>
<p>Deu para entender agora? Me mande um email dizendo o que você achou desse
exemplo e se você ficou com alguma dúvida. Até a próxima!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Ordenando strings no R</title>
      <link>https://lente.dev/posts/ordenando-strings/</link>
      <pubDate>Mon, 06 Mar 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/ordenando-strings/</guid>
      <description>Nem sempre é simples ordenar strings no R corretamente!</description>
      <content:encoded><![CDATA[<p>Recentemente a <a href="https://twitter.com/beamilz">Beatriz Milz</a> trouxe para o Slack
da Curso-R uma dúvida intrigante:</p>
<blockquote>
<p>[&hellip;] Quando ordeno com arrange uma coluna, tem um valor que começa com A que
aparece no final da lista!</p>
</blockquote>
<p>O exemplo dela envolvia ordenar uma coluna de textos de uma tabela. A ordenação
funcionava normalmente com <code>sort()</code>, mas não com <code>arrange()</code>. Veja a
demonstração a seguir:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Tabela exemplo</span>
</span></span><span class="line"><span class="cl"><span class="n">df</span> <span class="o">&lt;-</span> <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">(</span><span class="n">bebida</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Cerveja&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Cachaça&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Água&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Vinho&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Gim&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Tudo certo por aqui</span>
</span></span><span class="line"><span class="cl"><span class="nf">sort</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">bebida</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Água&#34;    &#34;Cachaça&#34; &#34;Cerveja&#34; &#34;Gim&#34;     &#34;Vinho&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Água fica por último!</span>
</span></span><span class="line"><span class="cl"><span class="n">dplyr</span><span class="o">::</span><span class="nf">arrange</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">bebida</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 5 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   bebida</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 Cachaça</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 2 Cerveja</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 3 Gim</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 4 Vinho</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 5 Água</span></span></span></code></pre></div><p>O nosso principal suspeito era o mesmo de qualquer problema com strings:
encoding ou, em bom português,
<a href="https://pt.wikipedia.org/wiki/Codifica%C3%A7%C3%A3o">codificação</a>. Contudo,
desta vez ele não é o culpado; os caracteres do texto estão sendo interpretados
e exibidos corretamente na saída de ambos os comandos, indicando que a causa da
ordenação incorreta era outra.</p>
<p>Em busca de uma resposta, resolvi ler a documentação da função <code>arrange()</code>. Para
a minha surpresa, descobri que ela tem um argumento <code>.locale</code> cujo valor por
padrão é &ldquo;o locale <code>&quot;C&quot;</code>&rdquo;&hellip; Mas, o que isso significa? Normalmente vemos
problemas de <a href="https://pt.wikipedia.org/wiki/Locale">locale</a> quando lidamos com
tempo, porque essa é a opção que determina o formato de exibição das datas
(<code>DD/MM/AAAA</code> no Brasil, <code>MM/DD/AAAA</code> nos EUA, etc.). Será que ela poderia ter
alguma coisa a ver com a ordenação de textos?</p>
<p>Seguindo as pistas na documentação da <code>arrange()</code>, eventualmente cheguei na
função <code>stringi::stri_opts_collator()</code>, que ajusta as opções do <em>ICU Collator</em>.
E foi aí que tudo fez sentido.</p>
<h2 id="collation">Collation</h2>
<p><a href="https://en.wikipedia.org/wiki/Collation"><em>Collation</em></a> é um termo em inglês que
descreve a compilação e ordenação de qualquer tipo de informação. A
(surpreendente!) realidade é que cada país e idioma tem regras diferentes de
ordenação alfabética, então é necessário escolher qual método de <em>collation</em> o R
vai usar através do locale.</p>
<p>Para ilustrar a função do locale, imagine um problema mais simples: queremos que
o R leia adequadamente uma data em alemão. Obviamente, ele não vai conseguir:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">lubridate</span><span class="o">::</span><span class="nf">dmy</span><span class="p">(</span><span class="s">&#34;6. März 2023&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning: All formats failed to parse. No formats found.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] NA</span></span></span></code></pre></div><p>Para corrigir isso, precisamos especificar o argumento <code>locale</code>, indicando para
o R que o conteúdo está escrito em alemão (<code>&quot;de_DE&quot;</code> para alemão da Alemanha):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">lubridate</span><span class="o">::</span><span class="nf">dmy</span><span class="p">(</span><span class="s">&#34;6. März 2023&#34;</span><span class="p">,</span> <span class="n">locale</span> <span class="o">=</span> <span class="s">&#34;de_DE&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;2023-03-06&#34;</span></span></span></code></pre></div><p>O chocante é que o mesmo vale para a ordem alfabética. Nós geralmente não
percebemos que tem algo errado com o locale da <em>collation</em> porque as regras de
ordenação são muito parecidas em todos os países, mas existem diferenças sutis
que causam problemas como o da Bea.</p>
<p>O programa que está tomando essas decisões de locale por trás dos panos se chama
<a href="https://github.com/unicode-org/icu">ICU</a>; esta biblioteca do C é a base do
stringi, o motor por trás do stringr e da <code>arrange()</code>. Como você pode imaginar,
o locale padrão da ICU é o da linguagem C de programação, que coloca letras
acentuadas no fim do alfabeto.</p>
<p>Sendo assim, podemos resolver a questão do <code>arrange()</code> especificando o nosso
locale (<code>&quot;pt_BR&quot;</code> para português do Brasil):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">dplyr</span><span class="o">::</span><span class="nf">arrange</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">bebida</span><span class="p">,</span> <span class="n">.locale</span> <span class="o">=</span> <span class="s">&#34;pt_BR&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 5 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   bebida</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 Água</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 2 Cachaça</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 3 Cerveja</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 4 Gim</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 5 Vinho</span></span></span></code></pre></div><p>É muito interessante ler a
<a href="https://unicode-org.github.io/icu/userguide/collation/">documentação</a> do ICU
sobre <em>collation</em>, pois ela deixa muito claro que é absolutamente impossível
criar um locale que atenda às necessidades de todos os países:</p>
<ul>
<li>Em lituano, o &ldquo;y&rdquo; fica entre o &ldquo;i&rdquo; e o &ldquo;k&rdquo;.</li>
<li>No espanhol tradicional, &ldquo;ch&rdquo; é tratado como uma única letra entre o &ldquo;c&rdquo; e o
&ldquo;d&rdquo;.</li>
<li>Em dinamarquês, &ldquo;Å&rdquo; é considerada uma letra separada que fica depois do &ldquo;Z&rdquo;.</li>
<li>Na Suécia, &ldquo;v&rdquo; e &ldquo;w&rdquo; são consideradas variações de uma mesma letra.</li>
<li>Em dicionários alemães, &ldquo;öf&rdquo; vem antes de &ldquo;of&rdquo;, mas em listas telefônicas a
ordem preferida é a contrária.</li>
</ul>
<p>O bom é que isso também esclarece o porquê da <code>sort()</code> funcionar, mas a
<code>arrange()</code> não. Enquanto a segunda usa o locale <code>&quot;C&quot;</code> por padrão, a primeira
usa o locale americano (<code>&quot;en_US&quot;</code> para inglês dos EUA)! Apesar de o locale
americano nos causar problemas com datas, ele é muito parecido com o brasileiro
na ordem alfabética e essencialmente ignora os acentos durante a <em>collation</em>.</p>
<h2 id="resumo">Resumo</h2>
<p>A função <code>arrange()</code> pode causar problemas na hora de ordenar textos em
português. Isso ocorre porque o locale de <em>collation</em> padrão coloca todas as
letras acentuadas no final do alfabeto, algo muito pouco usual no nosso idioma.
A solução é especificar o argumento <code>.locale = &quot;pt_BR&quot;</code> para que ela use o
locale apropriado ao nosso alfabeto.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Aleatoriedade com CSS</title>
      <link></link>
      <pubDate>Tue, 10 Jan 2023 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Advent of R com aor</title>
      <link>https://lente.dev/posts/aor-2022/</link>
      <pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/aor-2022/</guid>
      <description>Resolvendo o Advent of Code 2022 com o pacote {aor}!</description>
      <content:encoded><![CDATA[<p>Quem acompanha o blog talvez se lembre que ano passado eu fiz um
<a href="https://lente.dev/posts/aor-2021/">post</a> resolvendo todos os problemas do <a href="https://adventofcode.com/">Advent
of Code</a> de 2021 em R. Este ano eu voltei para a
festa, mas desta vez com um presente para todo mundo 🎁</p>
<h2 id="o-evento">O evento</h2>
<p>Se você não está por dentro, o Advent of Code é um <a href="https://pt.wikipedia.org/wiki/Calend%C3%A1rio_do_Advento">Calendário do
Advento</a> para quem
programa. Entre 1º de dezembro e o Natal de cada ano, os organizadores vão
disponibilizando 1 problema de programação por dia e o objetivo é chegar em 25
de dezembro com todos os 25 exercícios resolvidos.</p>
<p>Ano passado, no que eu chamei de Advent of R, eu me desafiei a de fato entrar no
ritmo e resolver todos os problemas <em>no dia em que eles fossem publicados</em>, em R
e documentando o processo no blog. Eu até consegui, mas foi extremamente
difícil! Este ano eu vou pegar mais leve e fazer as coisas com mais calma.</p>
<p>Mas eu não queria deixar o evento passar em branco&hellip; Em 2022, minha
contribuição para o Advent of R é um pacote para ajudar a comunidade toda 🎉</p>
<h2 id="o-pacote-aor">O pacote {aor}</h2>
<p>O objetivo do {aor} é ajudar todo mundo que programa R a resolver o Advent of
Code usando essa linguagem maravilhosa. Ele tem algumas funções que ajudam a
baixar os desafios e as suas entradas o mais rápido possível.</p>
<h3 id="instalação">Instalação</h3>
<p>Você pode instalar a versão em desenvolvimento do {aor} do
<a href="https://github.com/clente/aor">GitHub</a> usando o comando abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># install.packages(&#34;devtools&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">devtools</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;clente/aor&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="exemplo">Exemplo</h3>
<p>O uso básico do {aor} gira em torno das funções <code>day_start()</code> e
<code>day_continue()</code>. Por padrão, ambas as funções baixam os enunciados <em>do dia
atual</em>, mas vou usar um dia fixo (01/12/2022) para ficar mais fácil de entender:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Começar o problema do dia 01/12/2022 na pasta aoc2022/</span>
</span></span><span class="line"><span class="cl"><span class="n">aor</span><span class="o">::</span><span class="nf">day_start</span><span class="p">(</span><span class="s">&#34;2022-12-01&#34;</span><span class="p">,</span> <span class="s">&#34;aoc2022/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔ Fetched title.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔ Fetched puzzle.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔ Fetched input.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Arquivos criados</span>
</span></span><span class="line"><span class="cl"><span class="n">fs</span><span class="o">::</span><span class="nf">dir_tree</span><span class="p">(</span><span class="s">&#34;aoc2022/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; aoc2022/</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; └── 01_calorie_counting</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;     ├── input.txt</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;     └── puzzle.R</span></span></span></code></pre></div><p>Essa é a cara do arquivo <code>aoc2022/01_calorie_counting/puzzle.R</code> (note que eu
estou omitindo a maior parte das linhas do enunciado para que a saída não fique
muito longa):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># --- Day 1: Calorie Counting ---</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Santa&#39;s reindeer typically eat regular reindeer food, but they need a</span>
</span></span><span class="line"><span class="cl"><span class="c1"># lot of [magical energy](/2018/day/25) to deliver presents on Christmas.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># For that, their favorite snack is a special type of *star* fruit that</span>
</span></span><span class="line"><span class="cl"><span class="c1"># only grows deep in the jungle. The Elves have brought you on their</span>
</span></span><span class="line"><span class="cl"><span class="c1"># annual expedition to the grove where the fruit grows.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Find the Elf carrying the most Calories. *How many total Calories is</span>
</span></span><span class="line"><span class="cl"><span class="c1"># that Elf carrying?*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Your input can be found on the file below:</span>
</span></span><span class="line"><span class="cl"><span class="n">input</span> <span class="o">&lt;-</span> <span class="s">&#34;aoc2022/01_calorie_counting/input.txt&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Once you&#39;re done with part 1, run the following line to fetch part 2:</span>
</span></span><span class="line"><span class="cl"><span class="n">aor</span><span class="o">::</span><span class="nf">day_continue</span><span class="p">(</span><span class="s">&#34;2022-12-01&#34;</span><span class="p">,</span> <span class="s">&#34;aoc2022/01_calorie_counting/puzzle.R&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Quando você resolver a parte 1 do exercício, você pode rodar a última linha do
arquivo para automaticamente baixar a parte 2 ali mesmo!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">aor</span><span class="o">::</span><span class="nf">day_continue</span><span class="p">(</span><span class="s">&#34;2022-12-01&#34;</span><span class="p">,</span> <span class="s">&#34;aoc2022/01_calorie_counting/puzzle.R&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔ Fetched puzzle.</span></span></span></code></pre></div><p>E essa é a cara do arquivo logo depois de rodar <code>day_continue()</code> (de novo
omitindo a maior parte das linhas):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># --- Day 1: Calorie Counting ---</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Santa&#39;s reindeer typically eat regular reindeer food, but they need a</span>
</span></span><span class="line"><span class="cl"><span class="c1"># lot of [magical energy](/2018/day/25) to deliver presents on Christmas.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># For that, their favorite snack is a special type of *star* fruit that</span>
</span></span><span class="line"><span class="cl"><span class="c1"># only grows deep in the jungle. The Elves have brought you on their</span>
</span></span><span class="line"><span class="cl"><span class="c1"># annual expedition to the grove where the fruit grows.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Find the Elf carrying the most Calories. *How many total Calories is</span>
</span></span><span class="line"><span class="cl"><span class="c1"># that Elf carrying?*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Your input can be found on the file below:</span>
</span></span><span class="line"><span class="cl"><span class="n">input</span> <span class="o">&lt;-</span> <span class="s">&#34;aoc2022/01_calorie_counting/input.txt&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Once you&#39;re done with part 1, run the following line to fetch part 2:</span>
</span></span><span class="line"><span class="cl"><span class="n">aor</span><span class="o">::</span><span class="nf">day_continue</span><span class="p">(</span><span class="s">&#34;2022-12-01&#34;</span><span class="p">,</span> <span class="s">&#34;aoc2022/01_calorie_counting/puzzle.R&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># --- Part Two ---</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># By the time you calculate the answer to the Elves&#39; question, they&#39;ve</span>
</span></span><span class="line"><span class="cl"><span class="c1"># already realized that the Elf carrying the most Calories of food might</span>
</span></span><span class="line"><span class="cl"><span class="c1"># eventually *run out of snacks*.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Find the top three Elves carrying the most Calories. *How many Calories</span>
</span></span><span class="line"><span class="cl"><span class="c1"># are those Elves carrying in total?*</span></span></span></code></pre></div><p>Espero que vocês aproveitem o Advent of R com o {aor}! Boa sorte e boas festas
🎄</p>
]]></content:encoded>
    </item>
    <item>
      <title>VS Code no servidor</title>
      <link>https://lente.dev/posts/vscode-server/</link>
      <pubDate>Fri, 15 Jul 2022 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/vscode-server/</guid>
      <description>Como emular o RStudio Server usando o VS Code.</description>
      <content:encoded><![CDATA[<p>Uma das melhores funcionalidades do RStudio é, sem sombra de dúvidas, o
<a href="https://www.rstudio.com/products/rstudio/download-server/">RStudio Server</a>.
Para ser mais preciso, ele é a melhor <em>versão</em> do RStudio; esse produto é, na
verdade, uma integração entre a IDE RStudio e um programa de acesso remoto.</p>
<p>De forma bem resumida, ao instalar o RStudio Server em um servidor, você nunca
mais precisa se preocupar com SSH. Todo o acesso ao servidor passa a ser através
de uma interface web que é idêntica ao RStudio normal, o que significa que você
pode programar usando os recursos do seu servidor, mas com a mesmíssima IDE que
você já usa no dia-a-dia.</p>
<p>Mesmo depois que eu passei a
<a href="https://lente.dev/posts/vscode-r/">usar o VS Code</a> para
programar R no meu computador, eu continuei usando o RStudio Server no servidor
da empresa. Mês passado, entretanto, eu descobri uma funcionalidade incrível do
VS Code que me permitiu abandonar de uma vez por todas o RStudio: o
<a href="https://code.visualstudio.com/docs/remote/remote-overview">VS Code Remote Development</a>.</p>
<p>Diferentemente do RStudio Server, o Remote Development não é instalado no
servidor, mas sim no seu computador. Essa ferramenta usa SSH por trás dos panos
para trazer todos os arquivos do servidor até o seu VS Code local e, quando você
executa algum comando, ela faz o caminho reverso para rodar o código no
servidor.</p>
<p>Isso não é nada novo! Todo mundo que já usou SSH alguma vez na vida e precisou
abrir um editor de texto remoto (<code>vim</code> ou <code>nano</code>), provavelmente não vai
estranhar o modo como o Remote Development funciona. A única diferença é que o
RD traz o código até o VS Code e não até o seu terminal.</p>
<p>Há vantagens e desvantagens nessa abordagem: por um lado, o servidor não vai
precisar gastar recursos renderizando a interface do RStudio Server, mas por
outro, não tem um jeito muito simples de passar o seu acesso para outra pessoa
(dado que não é só um site que você acessa de qualquer lugar). A melhor solução
é sempre a que se encaixa melhor no seu fluxo de trabalho.</p>
<p>O processo para configurar o RD é bastante simples e pode ser encontrado
inteiramente na <a href="https://code.visualstudio.com/docs/remote/ssh-tutorial">página</a>
do Remote development via SSH. Em resumo, você precisa instalar a extensão,
conectar com o seu servidor via SSH e configurar as suas extensões para o
ambiente remoto.</p>
<p>O passo mais complexo é o último, mas mesmo ele é até que bastante intuitivo. Na
época eu tive dificuldade de entender que as minhas extensões não funcionavam no
modo remoto porque eu precisava instalá-las de novo! Essencialmente, eu
precisava configurar a extensão do R para funcionar com os programas do servidor
e não mais os da minha máquina.</p>
<p>E isso é tudo! Espero que este post tenha sido útil para apresentar uma
funcionalidade muito legal da IDE que eu tenho usado todos os dias pelos últimos
meses. Até a próxima :)</p>
<p>P.S.: Além da solução que eu apresentei, há ainda duas outras: o
<a href="https://www.rstudio.com/products/workbench/">RStudio Workbench</a> (um produto
pago da RStudio) passou a
<a href="https://support.rstudio.com/hc/en-us/articles/1500011478222-Using-VS-Code-Sessions-with-RStudio-Workbench">permitir</a>
o uso da interface do VS Code e, recentemente, a Microsoft anunciou o
<a href="https://code.visualstudio.com/blogs/2022/07/07/vscode-server">VS Code Server</a>,
que eu ainda não tive oportunidade de testar.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Magic no R com scryr</title>
      <link>https://lente.dev/posts/scryr/</link>
      <pubDate>Fri, 07 Jan 2022 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/scryr/</guid>
      <description>Um pacote R para acessar o Scryfall, uma API para Magic: The Gathering</description>
      <content:encoded><![CDATA[<p><a href="https://github.com/curso-r/scryr">scryr</a> é uma interface em R para o
<a href="https://scryfall.com/">Scryfall</a>, uma API incrível (e grátis!) de <em>Magic: The
Gathering</em>. Com o scryr você pode transformar dados de cartas em drata frames
nativos, permitindo integração imediata com qualquer fluxo tidy.</p>
<p>Atualmente há 2 famílias de funções principais: <code>cards</code> e <code>sets</code>. As outras 4
(<code>bulk_data</code>, <code>catalogs</code>, <code>rulings</code>, e <code>symbols</code>) são majoritariamente
auxiliares.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Instalar o scryr</span>
</span></span><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;scryr&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Carregar o scryr com o dplyr</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">scryr</span><span class="p">)</span></span></span></code></pre></div><h2 id="cartas">Cartas</h2>
<p>Essa família é, de longe, a mais complicada de entender. Antes de usá-la,
lembre-se de ler a documentação completa da
<a href="https://curso-r.github.io/scryr/reference/scry-cards.html"><code>scry_cards()</code></a>!
Para os curiosos, outras informações relevantes podem ser encontradas em
<a href="https://curso-r.github.io/scryr/articles/syntax.html"><code>vignette(&quot;syntax&quot;)</code></a>
(<em>Query Syntax</em>) e em
<a href="https://curso-r.github.io/scryr/articles/layouts.html"><code>vignette(&quot;layouts&quot;)</code></a>`
(<em>Layouts and Faces</em>).</p>
<p>A função mais importante aqui é
<a href="https://curso-r.github.io/scryr/reference/scry-cards.html"><code>scry_cards()</code></a>. Ela
retorna um data frame de cartas dada uma busca.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Vampiros lendários</span>
</span></span><span class="line"><span class="cl"><span class="n">vampires</span> <span class="o">&lt;-</span> <span class="nf">scry_cards</span><span class="p">(</span><span class="s">&#34;t:vampire t:legend&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Há muitas, muitas colunas</span>
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">vampires</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 48 × 70</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    id         name     set   lang  colors color_identity mana_cost   cmc</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    &lt;chr&gt;      &lt;chr&gt;    &lt;chr&gt; &lt;chr&gt; &lt;list&gt; &lt;list&gt;         &lt;chr&gt;     &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1 913dd06f-… Anje Fa… c19   en    &lt;chr … &lt;chr [2]&gt;      {1}{B}{R}     3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2 1bfac4ab-… Anje, M… vow   en    &lt;chr … &lt;chr [2]&gt;      {2}{B}{R}     4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3 b8630ae1-… Anowon,… voc   en    &lt;chr … &lt;chr [1]&gt;      {3}{B}{B}     5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4 bca84fc4-… Anowon,… znc   en    &lt;chr … &lt;chr [2]&gt;      {2}{U}{B}     4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5 e811f37a-… Arvad t… dom   en    &lt;chr … &lt;chr [2]&gt;      {3}{W}{B}     5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6 213ad4ba-… Ascenda… hop   en    &lt;chr … &lt;chr [1]&gt;      {4}{B}{B}     6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7 e5fb44d7-… Baron S… me1   en    &lt;chr … &lt;chr [1]&gt;      {5}{B}{B…     8</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8 487e843f-… Crovax … tpr   en    &lt;chr … &lt;chr [1]&gt;      {2}{B}{B}     4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9 2c58ce5e-… Drana, … c17   en    &lt;chr … &lt;chr [1]&gt;      {3}{B}{B}     5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10 31d0c37f-… Drana, … jmp   en    &lt;chr … &lt;chr [1]&gt;      {1}{B}{B}     3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 38 more rows, and 62 more variables: oracle_text &lt;chr&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   power &lt;chr&gt;, toughness &lt;chr&gt;, type_line &lt;chr&gt;, edhrec_rank &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   keywords &lt;list&gt;, layout &lt;chr&gt;, legalities &lt;list&gt;, oversized &lt;lgl&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   reserved &lt;lgl&gt;, oracle_id &lt;chr&gt;, mtgo_id &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   multiverse_ids &lt;list&gt;, tcgplayer_id &lt;int&gt;, cardmarket_id &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   uri &lt;chr&gt;, scryfall_uri &lt;chr&gt;, rulings_uri &lt;chr&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   prints_search_uri &lt;chr&gt;, artist &lt;chr&gt;, artist_ids &lt;list&gt;, …</span></span></span></code></pre></div><p>Note que várias colunas são list-columns com dados aninhados. Isso é uma
consequência do modelo de dados do Scryfall e é a principal razão do scryr
precisar de tibbles para funcionar. Mas não se preocupe! Todos os dados são
consistentes e bem documentados.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar cartas relacionadas a Anje</span>
</span></span><span class="line"><span class="cl"><span class="n">vampires</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">filter</span><span class="p">(</span><span class="n">name</span> <span class="o">==</span> <span class="s">&#34;Anje, Maid of Dishonor&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pull</span><span class="p">(</span><span class="n">all_parts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 2 × 6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   object       id         component  name     type_line   uri</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;chr&gt;        &lt;chr&gt;      &lt;chr&gt;      &lt;chr&gt;    &lt;chr&gt;       &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 related_card 1bfac4ab-… combo_pie… Anje, M… Legendary … https://api.s…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 2 related_card a6f374bc-… token      Blood    Token Arti… https://api.s…</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar a identidade de cor da Anje</span>
</span></span><span class="line"><span class="cl"><span class="n">vampires</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">filter</span><span class="p">(</span><span class="n">name</span> <span class="o">==</span> <span class="s">&#34;Anje Falkenrath&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pull</span><span class="p">(</span><span class="n">color_identity</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;B&#34; &#34;R&#34;</span></span></span></code></pre></div><p>Também há várias funções &ldquo;no singular&rdquo;, ou seja, funções que retornam 1 carta ao
invés de muitas. Elas são
<a href="https://curso-r.github.io/scryr/reference/scry-cards.html"><code>scry_card()</code></a> e
suas irmãs, todos métodos que encontram uma carta dado um certo identificador.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Usando ID</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_card</span><span class="p">(</span><span class="s">&#34;913dd06f-ed2f-4128-9c9d-9cd0d8a55425&#34;</span><span class="p">)</span><span class="o">$</span><span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Anje Falkenrath&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Usando nome</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_card_name</span><span class="p">(</span><span class="s">&#34;Anje Falkenrath&#34;</span><span class="p">)</span><span class="o">$</span><span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Anje Falkenrath&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Usando um número de colecionador e um set</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_card_number</span><span class="p">(</span><span class="m">37</span><span class="p">,</span> <span class="s">&#34;c19&#34;</span><span class="p">)</span><span class="o">$</span><span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Anje Falkenrath&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar um commander vampiro aleatório</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_card_random</span><span class="p">(</span><span class="s">&#34;t:vampire t:legend&#34;</span><span class="p">)</span><span class="o">$</span><span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Vito, Thorn of the Dusk Rose&#34;</span></span></span></code></pre></div><p>Se você não tiver certeza de qual carta você está procurando, não se preocupe. O
Scryfall também tem um endpoint que tenta autocompletar o nome de uma carta e o
scryr disponibiliza isso para que você nem precise sair do R para procurar uma
carta.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Olha lá ela</span>
</span></span><span class="line"><span class="cl"><span class="nf">autocomplete_name</span><span class="p">(</span><span class="s">&#34;falken&#34;</span><span class="p">)</span><span class="n">[12]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Anje Falkenrath&#34;</span></span></span></code></pre></div><h2 id="sets">Sets</h2>
<p>A outra família principal retorna informações sobre sets. De novo há muitas
list-columns, mas, novamente, todas são tratadas consistentemente; seguindo
<code>cards</code>, <code>sets</code> também tem uma função &ldquo;plural&rdquo; e uma função &ldquo;singular&rdquo;. Note que
<a href="https://curso-r.github.io/scryr/reference/scry-cards.html"><code>scry_cards()</code></a> é a
única que pode filtrar seus resultados com o argumento <code>q</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar todos os sets</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_sets</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 721 × 19</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    id     code  name  uri   scryfall_uri search_uri released_at set_type</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    &lt;chr&gt;  &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt;        &lt;chr&gt;      &lt;date&gt;      &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1 a6012… tunf  Unfi… http… https://scr… https://a… 2022-04-01  token</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2 b314f… unf   Unfi… http… https://scr… https://a… 2022-04-01  funny</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3 b11b2… pw22  Wiza… http… https://scr… https://a… 2022-03-05  promo</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4 5bd03… tnec  Neon… http… https://scr… https://a… 2022-02-18  token</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5 8bb11… tneo  Kami… http… https://scr… https://a… 2022-02-18  token</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6 5b4d9… nec   Neon… http… https://scr… https://a… 2022-02-18  command…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7 59a20… neo   Kami… http… https://scr… https://a… 2022-02-18  expansi…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8 78a7f… cc2   Comm… http… https://scr… https://a… 2022-01-28  command…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9 5c163… dbl   Inni… http… https://scr… https://a… 2022-01-28  draft_i…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10 8a673… y22   Alch… http… https://scr… https://a… 2021-12-09  expansi…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 711 more rows, and 11 more variables: card_count &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   parent_set_code &lt;chr&gt;, digital &lt;lgl&gt;, nonfoil_only &lt;lgl&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   foil_only &lt;lgl&gt;, icon_svg_uri &lt;chr&gt;, tcgplayer_id &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   mtgo_code &lt;chr&gt;, arena_code &lt;chr&gt;, block_code &lt;chr&gt;, block &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar um único set com um código</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_set</span><span class="p">(</span><span class="s">&#34;vow&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 19</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   id    code  name  mtgo_code arena_code tcgplayer_id uri   scryfall_uri</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt;     &lt;chr&gt;             &lt;int&gt; &lt;chr&gt; &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 8144… vow   Inni… vow       vow                2862 http… https://scr…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 11 more variables: search_uri &lt;chr&gt;, released_at &lt;date&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   set_type &lt;chr&gt;, card_count &lt;int&gt;, printed_size &lt;int&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   digital &lt;lgl&gt;, nonfoil_only &lt;lgl&gt;, foil_only &lt;lgl&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   block_code &lt;chr&gt;, block &lt;chr&gt;, icon_svg_uri &lt;chr&gt;</span></span></span></code></pre></div><h2 id="outras-famílias">Outras Famílias</h2>
<p>Todas as outras famílias retornam muito menos informações do que as acima. Deixo
vocês com uma pequena demontração do que o resto do scryr pode fazer:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar informações de um catálogo</span>
</span></span><span class="line"><span class="cl"><span class="nf">head</span><span class="p">(</span><span class="nf">scry_catalog</span><span class="p">(</span><span class="s">&#34;keyword-actions&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Meld&#34;        &#34;Bolster&#34;     &#34;Clash&#34;       &#34;Fateseal&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [5] &#34;Manifest&#34;    &#34;Monstrosity&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar regras de uma carta</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_ruling</span><span class="p">(</span><span class="s">&#34;913dd06f-ed2f-4128-9c9d-9cd0d8a55425&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   oracle_id                            source published_at comment</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;chr&gt;                                &lt;chr&gt;  &lt;date&gt;       &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 4dab6a96-4376-4aea-983d-406167993214 wotc   2019-08-23   If you disca…</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar informações sobre símbolos</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_symbols</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 34 × 11</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    symbol colors   cmc loose_variant english           gatherer_alterna…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    &lt;chr&gt;  &lt;list&gt; &lt;dbl&gt; &lt;chr&gt;         &lt;chr&gt;             &lt;list&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1 {X}    &lt;NULL&gt;   0   X             X generic mana    &lt;chr [2]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2 {Y}    &lt;NULL&gt;   0   Y             Y generic mana    &lt;NULL&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3 {Z}    &lt;NULL&gt;   0   Z             Z generic mana    &lt;NULL&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4 {0}    &lt;NULL&gt;   0   0             zero mana         &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5 {½}    &lt;NULL&gt;   0.5 ½             one-half generic… &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6 {1}    &lt;NULL&gt;   1   1             one generic mana  &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7 {2}    &lt;NULL&gt;   2   2             two generic mana  &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8 {3}    &lt;NULL&gt;   3   3             three generic ma… &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9 {4}    &lt;NULL&gt;   4   4             four generic mana &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10 {5}    &lt;NULL&gt;   5   5             five generic mana &lt;chr [1]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 24 more rows, and 5 more variables: transposable &lt;lgl&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   represents_mana &lt;lgl&gt;, appears_in_mana_costs &lt;lgl&gt;, funny &lt;lgl&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; #   svg_uri &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Processar um custo de mana</span>
</span></span><span class="line"><span class="cl"><span class="nf">parse_cost</span><span class="p">(</span><span class="s">&#34;2g2&#34;</span><span class="p">)</span><span class="o">$</span><span class="n">cost</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;{4}{G}&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar nomes dos arquivos de massa</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_bulk_files</span><span class="p">()</span><span class="o">$</span><span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Oracle Cards&#34;   &#34;Unique Artwork&#34; &#34;Default Cards&#34;  &#34;All Cards&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [5] &#34;Rulings&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Baixar (e processar) todas as regras da base do Scryfall</span>
</span></span><span class="line"><span class="cl"><span class="nf">scry_bulk_file</span><span class="p">(</span><span class="s">&#34;Rulings&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 44,486 × 4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    oracle_id                            source published_at comment</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    &lt;chr&gt;                                &lt;chr&gt;  &lt;date&gt;       &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1 0004ebd0-dfd6-4276-b4a6-de0003e94237 wotc   2004-10-04   If there ar…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   The &#34;comman…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   Certain car…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   If your com…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5 000e5d65-96c3-498b-bd01-72b1a1991850 wotc   2004-10-04   The target …</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6 0012bc78-e69d-4a67-a302-e5fe0dfd4407 wotc   2019-05-03   A land norm…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   You can alw…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   Pteramander…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   If a creatu…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10 001c6369-df13-427d-89df-718d5c09f382 wotc   2009-05-01   Vedalken He…</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 44,476 more rows</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Sites de pedra</title>
      <link>https://lente.dev/posts/sites-de-pedra/</link>
      <pubDate>Fri, 31 Dec 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/sites-de-pedra/</guid>
      <description>Chega de tecnologias sensíveis e frágeis. Sites precisam durar.</description>
      <content:encoded><![CDATA[<p>Eu não sou a primeira pessoa a dizer isso. Na verdade acho que esse assunto já
está até um pouco batido&hellip; Mas eu me recuso a parar de bater nessa tecla: sites
<strong>precisam</strong> ser feitos para durar.</p>
<p>Um dos melhores artigos que eu já li na internet se chama
<a href="https://jeffhuang.com/designed_to_last/"><em>This Page is Designed to Last</em></a>,
escrito por <a href="https://jeffhuang.com/">Jeff Huang</a>, um professor de Ciência da
Computação da Brown University. Nele, Jeff discute seus recentes problemas com
<a href="https://pt.wikipedia.org/wiki/Apodrecimento_de_links">apodrecimento de links</a> e
como é cada vez mais difícil confiar que uma página permanecerá de pé depois de
alguns anos.</p>
<p>As ferramentas de desenvolvimento web têm ficado cada vez mais complexas e, ao
mesmo tempo, a dificuldade de manter seu próprio conteúdo tem aumentado
proporcionalmente. Qual framework de JavaScript devemos usar hoje? React? Vue?
Angular? Essas ferramentas vão funcionar daqui 10 anos?</p>
<figure><img src="https://lente.dev/posts/stone-websites/road_pt.webp"/>
</figure>
<p>Muito por causa dessa dificuldade de conseguir manter seu próprio conteúdo vivo,
temos trocado a web pública por aplicativos de celular, redes sociais e sites
&ldquo;pré-prontos&rdquo;. Um dia o Instagram, o Twitter e o Wix vão sumir, inevitavelmente
deixando seu antigo conteúdo sem lar.</p>
<p>Quanta confiança você tem de que aquele perfil que você retuitou semana passada
vai continuar no ar daqui 5 anos? E se aquela página tivesse conteúdo valioso
para a sua pesquisa? O próprio Jeff nos dá algumas dicas de como criar páginas
feitas para durar:</p>
<ol>
<li>Use HTML/CSS puros.</li>
<li>Não minimize HTML.</li>
<li>Prefira uma página ao invés de várias.</li>
<li>Acabe com o <em>hotlinking</em>.</li>
<li>Use fontes nativas.</li>
<li>Comprima suas imagens.</li>
<li>Reduza o risco de links quebrados.</li>
</ol>
<p>O seu site vai ficar mais feioso? Possivelmente. O seu site vai ficar menos
moderno? Quase com certeza. O processo de manutenção vai ficar menos
automatizado? No início é muito provável que sim. Mas quais são os registros da
Antiguidade que ainda temos? Não são os belos tecidos ou as meticulosas
esculturas de madeira, são os textos talhados em pedra. Os nossos sites precisam
ser construídos com essa mentalidade.</p>
<h2 id="fazendo-a-minha-parte">Fazendo a Minha Parte</h2>
<p>Agora vamos falar sobre a página na qual você se encontra. Em primeiro lugar eu
tentei seguir ao máximo as dicas do Jeff, removendo a maior parte das
minimizações, optando majoritariamente por fontes nativas, hospedando minhas
próprias imagens, usando HTTPS e assim por diante. É verdade que eu uso o
<a href="https://gohugo.io/">Hugo</a> (será que esse link ainda funciona?) para gerar os
HTMLs dos posts a partir de arquivos Markdown, mas isso só afeta a minha criação
de novo conteúdo; tudo que já está aqui não tem motivo para mudar se o Hugo parar
de funcionar.</p>
<p>Mas eu tentei ir além. Em respeito às suas segurança e privacidade, eu também
removi <strong>todo</strong> o JavaScript do meu site. Pode testar! Desabilite o JS,
investigue as requisições realizadas, tudo deve continuar igual. Até o <em>syntax
highlighting</em> e a formatação de fórmulas são completamente estáticos. P.S.: se a
fórmula não estiver renderizada corretamente, basta <strong>atualizar seu navegador</strong>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Nada de JavaScript aqui:</span>
</span></span><span class="line"><span class="cl"><span class="n">f</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="m">2</span> <span class="o">*</span> <span class="n">x</span></span></span></code></pre></div>

<math display="block"><mrow><mrow><mtext>S</mtext><mtext>e</mtext><mtext>m</mtext><mtext>&nbsp;</mtext><mtext>J</mtext><mtext>S</mtext><mtext>&nbsp;</mtext><mtext>a</mtext><mtext>q</mtext><mtext>u</mtext><mtext>i</mtext><mtext>&nbsp;</mtext><mtext>t</mtext><mtext>a</mtext><mtext>m</mtext><mtext>b</mtext><mover><mtext>e</mtext><mo stretchy="false">ˊ</mo></mover><mtext>m</mtext><mtext>:</mtext><mtext>&nbsp;</mtext></mrow><mi>f</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo><mo>=</mo><msubsup><mo movablelimits="false">∫</mo><mrow><mo>−</mo><mi>∞</mi></mrow><mi>∞</mi></msubsup><mover><mi>f</mi><mo stretchy="false">^</mo></mover><mo form="prefix" stretchy="false">(</mo><mi>ξ</mi><mo form="postfix" stretchy="false">)</mo><msup><mi>e</mi><mrow><mn>2</mn><mi>π</mi><mi>i</mi><mi>ξ</mi><mi>x</mi></mrow></msup><mi>d</mi><mi>ξ</mi></mrow></math>

<p>Em retrospecto, o trabalho foi até menor do que eu imaginava. Tanto o
<a href="https://github.com/alecthomas/chroma">Chroma</a> quanto o
<a href="https://katex.org/">KaTeX</a> permitem baixar os seus CSSs e fontes para que eles
possam formatar código/matemática sem a necessidade de um plugin JavaScript.</p>
<p>Na verdade, eu removi <strong>todas</strong> as requisições externas do site. Desde as
imagens até as fontes e <em>stylesheets</em>, os recursos que utilizo são todos
servidos junto com a página. Isso evita vulnerabilidades e rastreamento
indesejado, além de acelerar um pouco a navegação.</p>
<p>E, falando em rastreamento indesejado, obviamente não estou usando nenhum
serviço da laia do Google Analytics. Para confirmar essa alegação, basta olhar
os resultados do <a href="https://themarkup.org/blacklight?url=lente.dev">Blacklight</a>
para este domínio.</p>
<figure><img src="https://lente.dev/posts/stone-websites/blacklight.webp"/>
</figure>
<p>Agora, sobre a velocidade da navegação, eu particularmente me esforcei bastante
para que o site fosse leve e responsivo. Ter um CSS minimalista e usar fontes
nativas ajudou muito nisso, mas várias outras otimização tiveram que ser
realizadas. No momento em que escrevo, o site tem todas as notas máximas no
<a href="https://pagespeed.web.dev/report?url=https%3A%2F%2Flente.dev%2F">Google Lighthouse</a>.</p>
<figure><img src="https://lente.dev/posts/stone-websites/pagespeed.webp"/>
</figure>
<p>Entretanto, a minha maior conquista foi no que toca a segurança e privacidade da
navegação. Seguindo as dicas da Mozilla, meu blog também atingiu a nota máxima
do <a href="https://observatory.mozilla.org/analyze/lente.dev">Mozilla Observatory</a> (e
em todos os outros índices externos que eles utilizam).</p>
<figure><img src="https://lente.dev/posts/stone-websites/observatory.webp"/>
</figure>
<p>Este último passo deu mais trabalho do que eu esperava. Uma das sugestões do
Observatory é remover absolutamente todos os CSS <em>inline</em>, o que é simples para
a maior parte do conteúdo, <a href="https://github.com/KaTeX/KaTeX/issues/1968">exceto</a>
para o KaTeX. No final eu acabei tendo que criar um script para limpar esses
estilos e passá-los automaticamente para um arquivo CSS separado.</p>
<p>Em resumo, navegando aqui você:</p>
<ul>
<li>Receberá apenas tráfego criptografado via HTTPS.</li>
<li>Não vai sentir nem cheiro de JavaScript.</li>
<li>Não fará nenhuma requisição para outros domínios por trás dos panos.</li>
<li>Não estará sendo rastreado por cookies ou analytics.</li>
<li>Terá a melhor experiência de desempenho que eu puder prover.</li>
<li>Estará protegido pelos mais modernos padrões de segurança web.</li>
</ul>
<p>Enfim, este é o meu site de pedra. Sinta-se em casa.</p>
<h2 id="atualização-de-2023-01-17">Atualização de 2023-01-17</h2>
<p>Desde que eu escrevi este post, muita coisa mudou no site! Eu troquei de CSS
mais de uma vez, dei uma bela simplificada na estrutura, removi as fontes
externas e adicionei algumas otimizações que se tornaram possíveis só nos
últimos meses. O principal, entretanto, continua igual: sem rastreadores, leve e
sem vulnerabilidades.</p>
<p>Na verdade, estou escrevendo esta atualização para falar só do KaTeX. Apesar de
ele atender aos meus requisitos, a gambiarra para tirar os CSS <em>inlines</em> estava
saindo do controle&hellip; Era difícil demais de manter e os arquivos CSS resultantes
começaram a ficar pesados.</p>
<p>Mas, por pura sorte, eu tentei resolver esse problema literalmente uma semana
depois de o <a href="https://en.wikipedia.org/wiki/MathML">MathML</a> começar a ser
suportado pelo <a href="https://caniuse.com/mathml">Chrome</a>. Para quem não conhece, o
MathML permite escrever equações matemáticas usando elementos HTML normais como
<code>&lt;math&gt;</code>; isso resolve perfeitamente o meu problema porque é o navegador quem
acerta o estilo da fonte, sem a necessidade de um monte de CSS por fora. Basta
usar um <a href="https://temml.org/">conversor</a> de LaTeX para MathML e pronto!</p>
<p>Sendo assim, se alguma equação do site não estiver aparecendo direito para você,
basta atualizar seu navegador que o problema provavelmente irá embora. Viva o
MathML!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Advent of R</title>
      <link>https://lente.dev/posts/aor-2021/</link>
      <pubDate>Tue, 28 Dec 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/aor-2021/</guid>
      <description>Resolvendo o Advent of Code 2021 com R!</description>
      <content:encoded><![CDATA[<p>O <a href="https://adventofcode.com">Advent of Code</a> é um
<a href="https://pt.wikipedia.org/wiki/Calend%C3%A1rio_do_Advento">Calendário do Advento</a>
desenvolvido por <a href="https://github.com/topaz">Eric Wastl</a> composto por 25
pequenos exercícios de programação que vão sendo disponibilizados, um a um,
entre 1º de dezembro e o Natal de cada ano.</p>
<p>Meu objetivo com o <strong>Advent of R</strong> foi resolver todos os problemas do
<a href="https://adventofcode.com/2021">Advent of Code 2021</a> em R e documentar o
processo. Todo dia entre 01/12/2021 e 25/12/2021 eu vou resolvi o novo problema,
documentei a minha solução e subi os meus scripts completos para um
<a href="https://github.com/curso-r/advent-of-r">repositório público</a> no GitHub.</p>
<p>Abaixo, cada seção representa um item de um dia do advent. Cada exercício foi
individualmente resolvido no
<a href="https://blog.curso-r.com/tags/advent-of-r">blog da Curso-R</a> no dia correto,
então todos começam com a minha opinião daquele exercício. Boas festas e bom
código!</p>
<h2 id="varredura-de-sonar-a">Varredura de Sonar (A)</h2>
<p>A parte 1 do <a href="https://adventofcode.com/2021/day/1">primeiro exercício</a> do AoC
envolve ler uma lista de números e ver quantas vezes os valores aumentam em
relação ao anterior. Em linguagem matemática, precisamos avaliar quantas vezes


<math><mrow><msub><mi>x</mi><mi>i</mi></msub><mo>&gt;</mo><msub><mi>x</mi><mrow><mi>i</mi><mo>−</mo><mn>1</mn><mtext>​</mtext></mrow></msub></mrow></math>

.</p>
<p>Por exemplo, suponha a seguinte lista:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 199</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 208</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 210</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 207</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 240</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 269</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 260</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 263</span></span></span></code></pre></div><p>Nesse caso, precisamos comparar cada número com o da linha anterior e verificar
se ele representa que a série aumentou, diminuiu ou manteve-se constante.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 199 (NA)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 208 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 210 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200 (diminuiu)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 207 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 240 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 269 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 260 (diminuiu)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 263 (aumentou)</span></span></span></code></pre></div><p>Tendo isso, podemos concluir que houve 7 aumentos na série exemplo e essa seria
a resposta do problema.</p>
<p>O meu código para resolver o exercício ficou bem enxuto. Bastou ler a lista de
número do arquivo disponibilizado como uma tabela e comparar seus valores com
o seu <code>dplyr::lag()</code>; depois disso um <code>dplyr::summarise()</code> contou o número de
<code>TRUE</code>s ignorando <code>NA</code>s.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/01a_sonar_sweep.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;depth&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">prev_depth</span> <span class="o">=</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">lag</span><span class="p">(</span><span class="n">depth</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">is_deeper</span> <span class="o">=</span> <span class="n">depth</span> <span class="o">&gt;</span> <span class="n">prev_depth</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">n_deeper</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">is_deeper</span><span class="p">,</span> <span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">n_deeper</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1228</span></span></span></code></pre></div><h2 id="varredura-de-sonar-b">Varredura de Sonar (B)</h2>
<p>A segunda parte, entretanto, aumenta (com o perdão do trocadilho) a dificuldade.
Dessa vez precisamos somar uma janela de 3 valores e comparar com a próxima
janela, ou seja, verificar quantas vezes


<math><mrow><msubsup><mo movablelimits="false">∑</mo><mrow><mi>k</mi><mo>=</mo><mi>i</mi></mrow><mrow><mi>i</mi><mo>+</mo><mn>2</mn></mrow></msubsup><msub><mi>x</mi><mi>k</mi></msub><mo>≥</mo><msubsup><mo movablelimits="false">∑</mo><mrow><mi>k</mi><mo>=</mo><mi>i</mi><mo>−</mo><mn>1</mn></mrow><mrow><mi>i</mi><mo>+</mo><mn>1</mn></mrow></msubsup><msub><mi>x</mi><mi>k</mi></msub></mrow></math>
.</p>
<p>Observe como as janelas funcionam:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 199  A</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200  A B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 208  A B C</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 210    B C D</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200  E   C D</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 207  E F   D</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 240  E F G</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 269    F G H</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 260      G H</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 263        H</span></span></span></code></pre></div><p>Nesse exemplo precisaríamos somar os números da janela A (199, 200, 208) e
testar se isso é maior que a soma dos números da janela B (200, 208, 210). Então
compararíamos B com C, C com D e assim por diante.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># A: 607 (NA)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># B: 618 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># C: 618 (não mudou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># D: 617 (diminuiu)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># E: 647 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># F: 716 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># G: 769 (aumentou)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># H: 792 (aumentou)</span></span></span></code></pre></div><p>Alterando o código da primeira parte, eu criei as janelas usando <code>dplyr::lead()</code>
e depois comparei as somas utilizando o mesmo <code>dplyr::lag()</code>. Mais uma vez o
<code>dplyr::summarise()</code> contou o número de <code>TRUE</code>s ignorando <code>NA</code>s.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/01b_sonar_sweep.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;depth&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">depth1</span> <span class="o">=</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">lead</span><span class="p">(</span><span class="n">depth</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">depth2</span> <span class="o">=</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">lead</span><span class="p">(</span><span class="n">depth</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">sum_depth</span> <span class="o">=</span> <span class="n">depth</span> <span class="o">+</span> <span class="n">depth1</span> <span class="o">+</span> <span class="n">depth2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">prev_sum_depth</span> <span class="o">=</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">lag</span><span class="p">(</span><span class="n">sum_depth</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">is_deeper</span> <span class="o">=</span> <span class="n">sum_depth</span> <span class="o">&gt;</span> <span class="n">prev_sum_depth</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">n_deeper</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">is_deeper</span><span class="p">,</span> <span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">n_deeper</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1257</span></span></span></code></pre></div><h2 id="mergulhe-a">Mergulhe (A)</h2>
<p>A parte 1 do <a href="https://adventofcode.com/2021/day/2">segundo dia</a> do AoC pede para
lermos uma lista de comandos para um submarino e calcular a sua posição final.
Os comandos possíveis são <code>forward X</code> (soma X à posição horizontal), <code>up X</code>
(subtrai X da profundidade) e <code>down X</code> (soma X à profundidade), então precisamos
fazer um <code>dplyr::group_by(command == &quot;forward&quot;)</code> para que um grupo represente
a posição horizontal e um represente a profundidade.</p>
<p>Para concluir o código, como a resposta final é a posição horizontal
multiplicada pela profundidade, temos que fazer um <code>prod()</code> ao final:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/02a_dive.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_delim</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;command&#34;</span><span class="p">,</span> <span class="s">&#34;x&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;up&#34;</span><span class="p">,</span> <span class="o">-</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;forward&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="nf">prod</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1727835</span></span></span></code></pre></div><h2 id="mergulhe-b">Mergulhe (B)</h2>
<p>A parte 2 complica um pouco a nossa vida. Os mesmos comandos agora possuem outro
significado:</p>
<ul>
<li><code>down X</code> aumenta a mira em X unidades</li>
<li><code>up X</code> diminui a mira em X unidades.</li>
<li><code>forward X</code> faz duas coisas:
<ul>
<li>Aumenta a posição horizontal em X unidades.</li>
<li>Aumenta a profundidade em X vezes a mira atual.</li>
</ul>
</li>
</ul>
<p>O meu código da primeira parte não permitiria resolver isso de forma eficiente.
Minha solução foi fazer uma <code>cumsum()</code> da posição horizontal e uma da mira, que
são as partes mais simples. Depois eu calculei a profundidade com
<code>cumsum(aim * x)</code> (dado que a mira tinha sido calculada no passo anterior).</p>
<p>A saída, mais uma vez é o produto entre a posição horizontal e a profundidade.
Dessa vez a resposta vai estar na última linha da tabela, então o código precisa
de um <code>tail(1)</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/02a_dive.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_delim</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;command&#34;</span><span class="p">,</span> <span class="s">&#34;x&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">horizontal</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;forward&#34;</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">horizontal</span> <span class="o">=</span> <span class="nf">cumsum</span><span class="p">(</span><span class="n">horizontal</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">aim</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;down&#34;</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">aim</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;up&#34;</span><span class="p">,</span> <span class="o">-</span><span class="n">x</span><span class="p">,</span> <span class="n">aim</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">aim</span> <span class="o">=</span> <span class="nf">cumsum</span><span class="p">(</span><span class="n">aim</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">depth</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">command</span> <span class="o">==</span> <span class="s">&#34;forward&#34;</span><span class="p">,</span> <span class="n">aim</span> <span class="o">*</span> <span class="n">x</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">depth</span> <span class="o">=</span> <span class="nf">cumsum</span><span class="p">(</span><span class="n">depth</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">output</span> <span class="o">=</span> <span class="n">horizontal</span> <span class="o">*</span> <span class="n">depth</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">utils</span><span class="o">::</span><span class="nf">tail</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1544000595</span></span></span></code></pre></div><h2 id="diagnóstico-binário-a">Diagnóstico Binário (A)</h2>
<p>Na primeira parte do <a href="https://adventofcode.com/2021/day/3">terceiro dia</a> do AoC
somos apresentados aos diagnósticos do submarino. Cada linha é composta por um
número binário e precisamos carclular, a partir deles, os índices gama e
épsilon.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 00100</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 11110</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10110</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10111</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10101</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 01111</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 00111</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 11100</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10000</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 11001</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 00010</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 01010</span></span></span></code></pre></div><p>Cada bit do fator gama é igual ao valor mais comum do bit correspondente na
entrada, enquanto o épsilon funciona ao contrário. No exemplo acima, o primeiro
bit mais comum é 1 e o segundo é 0, então o índice gama começará com 10&hellip; e o
índice épsilon começará com 01&hellip;</p>
<p>O meu código quebra os bits da entrada com <code>tidyr::separate()</code> e calcula o valor
mais frequente com <code>names(sort(-table(.x)))[1]</code> (a moda estatística). É
importante lembrar que épsilon é o oposto, então eu troquei todos os bits de
gama com <code>stringr::str_replace_all()</code>. A resposta final é a multiplicação
de gama por épsilon na base decimal.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/03a_binary_diagnostic.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;reading&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">reading</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;B&#34;</span><span class="p">,</span> <span class="m">0</span><span class="o">:</span><span class="m">12</span><span class="p">),</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">B0</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise_all</span><span class="p">(</span><span class="o">~</span><span class="nf">names</span><span class="p">(</span><span class="nf">sort</span><span class="p">(</span><span class="o">-</span><span class="nf">table</span><span class="p">(</span><span class="n">.x</span><span class="p">)))</span><span class="n">[1]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unite</span><span class="p">(</span><span class="s">&#34;gamma&#34;</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">everything</span><span class="p">(),</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">epsilon</span> <span class="o">=</span> <span class="n">gamma</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span><span class="s">&#34;0&#34;</span><span class="p">,</span> <span class="s">&#34;!&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span><span class="s">&#34;1&#34;</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span><span class="s">&#34;!&#34;</span><span class="p">,</span> <span class="s">&#34;1&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nf">strtoi</span><span class="p">(</span><span class="n">base</span> <span class="o">=</span> <span class="m">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">gamma</span> <span class="o">=</span> <span class="nf">strtoi</span><span class="p">(</span><span class="n">gamma</span><span class="p">,</span> <span class="n">base</span> <span class="o">=</span> <span class="m">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">output</span> <span class="o">=</span> <span class="n">gamma</span> <span class="o">*</span> <span class="n">epsilon</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">output</span><span class="p">)</span></span></span></code></pre></div><h2 id="diagnóstico-binário-b">Diagnóstico Binário (B)</h2>
<p>O segundo item desse dia foi o mais difícil de todos, ainda mais considerando
que eu tento resolver tudo em apenas uma pipeline. Usando os mesmos dados,
precisamos obter a taxa de O₂ e de CO₂ do submarino, sendo que as regras
são as seguintes:</p>
<ol>
<li>
<p>Jogue fora os número que não atendem ao critério daquele gás.</p>
</li>
<li>
<p>Se restar apenas 1 número, essa é a taxa daquele gás.</p>
</li>
<li>
<p>Caso contrário, repita o processo com o próximo bit.</p>
</li>
</ol>
<p>E quais são os critérios?</p>
<ul>
<li>
<p>Para o oxigênio, determinamos o valor mais comum para o bit atual e jogamos
fora todos os números que diferem, nessa posição, desse valor. Se 0 e 1 forem
igualmente comuns, manter apenas os números com 1 no bit considerado.</p>
</li>
<li>
<p>Para gás carbônico, determinamos o valor menos comum para o bit atual e
jogamos fora todos os números que diferem, nessa posição, desse valor. Se 0 e 1
forem igualmente comuns, manter apenas os números com 0 no bit considerado.</p>
</li>
</ul>
<p>O primeiro passo da minha solução foi criar uma função que calcula a anti-moda
de um vetor. Ela difere da função usada no item anterior somente pelo sinal de
subtração, mas isso garante a ela uma propriedade importante: se 0 e 1 empatarem
na contagem, ela retorna o valor que vem antes na ordem alfabética, ou seja, 0.
Dessa forma a função <code>antimode()</code> realiza exatamente a operação que precisamos
para determinar a taxa de gás carbônico.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">antimode</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="nf">names</span><span class="p">(</span><span class="nf">sort</span><span class="p">(</span><span class="nf">table</span><span class="p">(</span><span class="n">x</span><span class="p">)))</span><span class="n">[1]</span></span></span></code></pre></div><p>A função abaixo é uma versão recursiva do cálculo das taxas dos gases. A coluna
<code>current</code> é só um atalho para deixar o filtro mais enxuto, pois ela não passa da
do bit atual. O <code>op()</code>, porém, é a chave que nos permite usar a mesma função
para calcular O₂ e CO₂; por padrão a função filtra os valores iguais à
anti-moda, mas, com <code>co2 = FALSE</code>, ela filtra os valores diferentes da
anti-moda, atendendo ao critério do oxigênio (incluindo o desempate)!</p>
<p>A última linha chama a função de novo para o próximo bit, resolvendo o cálculo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">gas</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">co2</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="n">bit</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condição de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">bit</span> <span class="o">&gt;</span> <span class="m">12</span> <span class="o">||</span> <span class="nf">nrow</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">==</span> <span class="m">1</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Escolher o operador apropriado</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">co2</span><span class="p">)</span> <span class="n">op</span> <span class="o">&lt;-</span> <span class="n">`==`</span> <span class="kr">else</span> <span class="n">op</span> <span class="o">&lt;-</span> <span class="n">`!=`</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Filtrar usando antimode() e fazer a recursão</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">current</span> <span class="o">=</span> <span class="n">.data[</span><span class="nf">[names</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="n">[bit]]]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="nf">op</span><span class="p">(</span><span class="n">current</span><span class="p">,</span> <span class="nf">antimode</span><span class="p">(</span><span class="n">current</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">current</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">find_rating</span><span class="p">(</span><span class="n">co2</span> <span class="o">=</span> <span class="n">co2</span><span class="p">,</span> <span class="n">bit</span> <span class="o">=</span> <span class="n">bit</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Só nos resta aplicar essa função na lista de números. Para tentar manter o fim
do código em uma pipeline só (já que não foi possível com o resto), eu usei
<code>rep_len(list(df), 2)</code> para duplicar a base e poder aplicar <code>gas()</code> e
<code>gas(co2 = FALSE)</code> em uma linha só com <code>purrr::map2_dfr()</code>. O final do código
deixa cada taxa em uma linha, junta os seu bits, as converte para decimal e
multiplica seus valores. Essa é a saída.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/03b_binary_diagnostic.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;reading&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">reading</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;B&#34;</span><span class="p">,</span> <span class="m">0</span><span class="o">:</span><span class="m">12</span><span class="p">),</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">B0</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">list</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rep_len</span><span class="p">(</span><span class="m">2</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map2_dfr</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="n">gas</span><span class="p">,</span> <span class="nf">\</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="nf">gas</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="kc">FALSE</span><span class="p">)),</span> <span class="o">~</span><span class="nf">.y</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unite</span><span class="p">(</span><span class="s">&#34;reading&#34;</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">everything</span><span class="p">(),</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">reading</span> <span class="o">=</span> <span class="nf">strtoi</span><span class="p">(</span><span class="n">reading</span><span class="p">,</span> <span class="n">base</span> <span class="o">=</span> <span class="m">2</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">output</span> <span class="o">=</span> <span class="nf">prod</span><span class="p">(</span><span class="n">reading</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">output</span><span class="p">)</span></span></span></code></pre></div><h2 id="lula-gigante-a">Lula Gigante (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/4">quarto dia</a> do AoC foi talvez o mais
interessante até agora. Na primeira parte, precisávamos calcular a pontuação da
cartela vencedora de um
<a href="https://en.wikipedia.org/wiki/Bingo_(American_version)">bingo americano</a>: cada
cartela é composta por 5 linhas e 5 colunas de números que devem ser riscados
conforme eles são anunciados pelo sistema do submarino. A primeira cartela a
riscar todos os números de uma linha ou coluna é a vencedora e sua pontuação é
a soma de todos os números não riscados multiplicada pelo último número
anunciado.</p>
<p>A entrada era composta por uma linha com os números anunciados em sequência e,
posteriormente, todas as cartelas da platéia:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 22 13 17 11  0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  8  2 23  4 24</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 21  9 14 16  7</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  6 10  3 18  5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  1 12 20 15 19</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  3 15  0  2 22</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  9 18 13 17  5</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 19  8  7 25 23</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 20 11 10 24  4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 14 21 16 12  6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 14 21 17 24  4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10 16 15  9 19</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 18  8 23 26 20</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 22 11 13  6  5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  2  0 12  3  7</span></span></span></code></pre></div><p>Eu escolhi um caminho simples para resolver o problema, apesar de o código não
ter ficado tão bom assim. Primeiro eu li a sequência de números e criei uma
função que transpunha uma matrix numérica e a empilhava com a original.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Processar os números sorteados</span>
</span></span><span class="line"><span class="cl"><span class="n">draws</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/04a_giant_squid.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.numeric</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Converter as colunas de uma matrix para linhas e empilhar</span>
</span></span><span class="line"><span class="cl"><span class="n">cols_to_rows</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">board</span><span class="p">,</span> <span class="o">-</span><span class="n">id</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.matrix</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">t</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">(</span><span class="n">rownames</span> <span class="o">=</span> <span class="s">&#34;id&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;C&#34;</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">board</span> <span class="o">=</span> <span class="n">df</span><span class="o">$</span><span class="n">board</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">relocate</span><span class="p">(</span><span class="n">board</span><span class="p">,</span> <span class="n">id</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">,</span> <span class="s">&#34;board&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;N&#34;</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>O objetivo de <code>cols_to_rows()</code> era criar uma tabela final com todas as linhas
das cartelas e também todas as suas colunas; isso permitiu que eu riscasse os
números sorteados aplicando <code>dplyr::na_if()</code> indiscriminadamente. Quando alguma
linha da tabela fosse formada somente por <code>NA</code>s (indicando que uma linha ou
coluna de alguma cartela estava completa), bastava extrair a cartela original,
somar os seus valores não-<code>NA</code> e multiplicar o resultado pelo número sorteado
mais recente. A função utilizada para isso se chamava <code>winning_score()</code> e
operava recursivamente para poupar tempo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Calcular a pontuação da cartela vencedora</span>
</span></span><span class="line"><span class="cl"><span class="n">winning_score</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">draws</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Marcar o número sorteado com NA (nas linhas e colunas)</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">N1</span><span class="o">:</span><span class="n">N5</span><span class="p">),</span> <span class="n">dplyr</span><span class="o">::</span><span class="n">na_if</span><span class="p">,</span> <span class="n">draws[1]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Filtrar possíveis linhas/colunas completas</span>
</span></span><span class="line"><span class="cl">  <span class="n">win</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">if_all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">N1</span><span class="o">:</span><span class="n">N5</span><span class="p">),</span> <span class="n">is.na</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Se houver pelo menos uma linha/coluna completa...</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">win</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Extrair a cartela vencedora, somar os não-NA e multiplicar por draws[1]</span>
</span></span><span class="line"><span class="cl">    <span class="n">output</span> <span class="o">&lt;-</span> <span class="n">df</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">id</span> <span class="o">==</span> <span class="n">win</span><span class="o">$</span><span class="n">id</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_starts</span><span class="p">(</span><span class="n">board</span><span class="p">,</span> <span class="s">&#34;R&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">id</span><span class="p">,</span> <span class="o">-</span><span class="n">board</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_dbl</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nf">sum</span><span class="p">(</span><span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">magrittr</span><span class="o">::</span><span class="nf">multiply_by</span><span class="p">(</span><span class="n">draws[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Retornar a pontuação</span>
</span></span><span class="line"><span class="cl">    <span class="kr">return</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Recursão para o próximo sorteio</span>
</span></span><span class="line"><span class="cl">  <span class="nf">winning_score</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">draws[</span><span class="m">-1</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler cartelas, empilhas linhas com colunas e riscar usando NAs</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/04a_giant_squid.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">skip</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;C&#34;</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">board</span> <span class="o">=</span> <span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">row_number</span><span class="p">()</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span> <span class="o">%/%</span> <span class="m">5</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">board</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">id</span> <span class="o">=</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;R&#34;</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_split</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map_dfr</span><span class="p">(</span><span class="n">cols_to_rows</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">winning_score</span><span class="p">(</span><span class="n">draws</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 33348</span></span></span></code></pre></div><h2 id="lula-gigante-b">Lula Gigante (B)</h2>
<p>O segundo item do problema pedia o contrário: calcular a pontuação da última
cartela a ter uma linha ou coluna completa, ou seja, da cartela perdedora. Na
minha solução todo o código permaneceu igual, salvo pela função
<code>winning_score()</code>, que virou <code>loosing_score()</code>. A grande novidade é que, quando
o programa encontrava uma cartela vencedora, ele verificava se aquela era a
última. Se não fosse, ele removia aquela cartela da tabela e, se fosse, ele
retornava a pontuação.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Calcular a pontuação da cartela perdedora</span>
</span></span><span class="line"><span class="cl"><span class="n">loosing_score</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">draws</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Marcar o número sorteado com NA (nas linhas e colunas)</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">N1</span><span class="o">:</span><span class="n">N5</span><span class="p">),</span> <span class="n">dplyr</span><span class="o">::</span><span class="n">na_if</span><span class="p">,</span> <span class="n">draws[1]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Filter possible complete rows or cols</span>
</span></span><span class="line"><span class="cl">  <span class="n">win</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">if_all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">N1</span><span class="o">:</span><span class="n">N5</span><span class="p">),</span> <span class="n">is.na</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Se houver pelo menos uma linha/coluna completa...</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">win</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Se restasse apenas uma cartela, calcular a sua pontuação</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">id</span><span class="p">))</span> <span class="o">==</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Extrair a cartela perdedora, somar os não-NA e multiplicar por draws[1]</span>
</span></span><span class="line"><span class="cl">      <span class="n">output</span> <span class="o">&lt;-</span> <span class="n">df</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_starts</span><span class="p">(</span><span class="n">board</span><span class="p">,</span> <span class="s">&#34;R&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">id</span><span class="p">,</span> <span class="o">-</span><span class="n">board</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_dbl</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nf">sum</span><span class="p">(</span><span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">magrittr</span><span class="o">::</span><span class="nf">multiply_by</span><span class="p">(</span><span class="n">draws[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Retornar a pontuação</span>
</span></span><span class="line"><span class="cl">      <span class="kr">return</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Jogar fora cartelas que já venceram</span>
</span></span><span class="line"><span class="cl">    <span class="n">df</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="o">!</span><span class="n">id</span> <span class="o">%in%</span> <span class="n">win</span><span class="o">$</span><span class="n">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Recursão para o próximo sorteio</span>
</span></span><span class="line"><span class="cl">  <span class="nf">loosing_score</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">draws[</span><span class="m">-1</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="aventura-hidrotermal-a">Aventura Hidrotermal (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/5">quinto dia</a> do AoC foi um pouco mais
tranquilo do que o anterior porque eu tive ajuda da incrível
<a href="https://twitter.com/renata_mh">Renata Hirota</a>. Hoje tínhamos as coordenadas
cartesianas do início e do fim de tubulações submarinas e o objetivo era
descobrir quantos pontos do plano tinham mais de uma tubulação passando por
eles. No primeiro item deveríamos considerar apenas as tubulações verticais e
horizontais.</p>
<ul>
<li>
<p>Uma entrada do tipo <code>1,1 -&gt; 1,3</code> cobria os pontos <code>1,1</code>, <code>1,2</code> e <code>1,3</code>.</p>
</li>
<li>
<p>Uma entrada do tipo <code>9,7 -&gt; 7,7</code> cobria os pontos <code>9,7</code>, <code>8,7</code> e <code>7,7</code>.</p>
</li>
</ul>
<p>A minha ideia começava filtrando os pontos em que <code>x1 == x2</code> ou <code>y1 == y2</code> e
expandindo as coordenadas para criar uma lista que contivesse todos os pontos
pelos quais as tubulações passavam. Eu resolvi isso com o <code>paste(x1:x2, y1:y2)</code>,
pois a <code>paste()</code> repetiria a coordenada que não muda ao longo da coordenada que
muda: <code>paste(9:7, 7:7) := &quot;9 7&quot; &quot;8 7&quot; &quot;7 7&quot;</code>.</p>
<p>Depois disso bastava contar o números de ocorrências de cada ponto do plano,
filtrar aqueles que ocorriam mais de 1 vez e contar quantos pontos restavam.
Esta era a saída do problema.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/05a_hydrothermal_venture.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_csv</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;x1&#34;</span><span class="p">,</span> <span class="s">&#34;y1x2&#34;</span><span class="p">,</span> <span class="s">&#34;y2&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">sep</span> <span class="o">=</span> <span class="s">&#34; -&gt; &#34;</span><span class="p">,</span> <span class="n">col</span> <span class="o">=</span> <span class="s">&#34;y1x2&#34;</span><span class="p">,</span> <span class="n">into</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;y1&#34;</span><span class="p">,</span> <span class="s">&#34;x2&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">x1</span> <span class="o">==</span> <span class="n">x2</span> <span class="o">|</span> <span class="n">y1</span> <span class="o">==</span> <span class="n">y2</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dif_x</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">x2</span><span class="p">,</span> <span class="n">seq</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dif_y</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">seq</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">coord</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">dif_x</span><span class="p">,</span> <span class="n">dif_y</span><span class="p">,</span> <span class="n">paste</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">coord</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">count</span><span class="p">(</span><span class="n">coord</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">nrow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 7142</span></span></span></code></pre></div><h2 id="aventura-hidrotermal-b">Aventura Hidrotermal (B)</h2>
<p>O segundo item parecia bastante mais complexo, pois agora deveríamos considerar
todas as tubulações da entrada, removendo o <code>dplyr::filter()</code> do item anterior.
Mas uma especificação do enunciado facilitou tudo: todas as linhas diagonais
tinham inclinação de 45 graus.</p>
<ul>
<li>
<p>Uma entrada do tipo <code>1,1 -&gt; 3,3</code> cobria os pontos <code>1,1</code>, <code>2,2</code> e <code>3,3</code>.</p>
</li>
<li>
<p>Uma entrada do tipo <code>9,7 -&gt; 7,9</code> cobria os pontos <code>9,7</code>, <code>8,8</code> e <code>7,9</code>.</p>
</li>
</ul>
<p>Isso significa que a estratégia do <code>paste()</code> continuava funcionando! Note que
<code>paste(1:3, 1:3) := &quot;1 1&quot; &quot;2 2&quot; &quot;3 3&quot;</code>, então bastou tirar o <code>dplyr::filter()</code>
que a solução estava pronta.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/05b_hydrothermal_venture.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_csv</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;x1&#34;</span><span class="p">,</span> <span class="s">&#34;y1x2&#34;</span><span class="p">,</span> <span class="s">&#34;y2&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">sep</span> <span class="o">=</span> <span class="s">&#34; -&gt; &#34;</span><span class="p">,</span> <span class="n">col</span> <span class="o">=</span> <span class="s">&#34;y1x2&#34;</span><span class="p">,</span> <span class="n">into</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;y1&#34;</span><span class="p">,</span> <span class="s">&#34;x2&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dif_x</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">x2</span><span class="p">,</span> <span class="n">seq</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dif_y</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">seq</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">coord</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">dif_x</span><span class="p">,</span> <span class="n">dif_y</span><span class="p">,</span> <span class="n">paste</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">coord</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">count</span><span class="p">(</span><span class="n">coord</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">nrow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 20012</span></span></span></code></pre></div><h2 id="peixes-lanterna-a">Peixes-lanterna (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/6">dia 6</a> do AoC me pegou um pouco de
surpresa. O primeiro item foi tranquilo de fazer: a entrada era uma lista de
números que representavam os &ldquo;contadores biológicos&rdquo; de um cardume de
peixes-lanterna e precisávamos retornar o número de peixes depois de 80 dias.</p>
<p>Os peixes adultos demoram 7 dias (contador vai de 6 até 0) para gerar um novo
peixe bebê e um peixe bebê demora 9 dias (contador vai de 8 até 0) para gerar
seu primeiro filhote.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">Estado</span> <span class="n">inicial</span>   <span class="o">:</span> <span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">1</span> <span class="n">dia</span> <span class="o">:</span> <span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">2</span> <span class="n">dias</span><span class="o">:</span> <span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">3</span> <span class="n">dias</span><span class="o">:</span> <span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">4</span> <span class="n">dias</span><span class="o">:</span> <span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">5</span> <span class="n">dias</span><span class="o">:</span> <span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">6</span> <span class="n">dias</span><span class="o">:</span> <span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">7</span> <span class="n">dias</span><span class="o">:</span> <span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">8</span> <span class="n">dias</span><span class="o">:</span> <span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span>  <span class="m">9</span> <span class="n">dias</span><span class="o">:</span> <span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">10</span> <span class="n">dias</span><span class="o">:</span> <span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">11</span> <span class="n">dias</span><span class="o">:</span> <span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">12</span> <span class="n">dias</span><span class="o">:</span> <span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">13</span> <span class="n">dias</span><span class="o">:</span> <span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">14</span> <span class="n">dias</span><span class="o">:</span> <span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">15</span> <span class="n">dias</span><span class="o">:</span> <span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">16</span> <span class="n">dias</span><span class="o">:</span> <span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">17</span> <span class="n">dias</span><span class="o">:</span> <span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="n">Depois</span> <span class="n">de</span> <span class="m">18</span> <span class="n">dias</span><span class="o">:</span> <span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">5</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">6</span><span class="p">,</span><span class="m">7</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span><span class="p">,</span><span class="m">8</span></span></span></code></pre></div><p>O meu código até que ficou bem simples. Precisei apenas de uma função que, todo
dia, subtraia 1 de todos os contadores, criava 1 peixe com contador 8 para
cada peixe com contador -1 e, por fim, subia todos os peixes com contador -1
para 6.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Rodar n cíclos de reprodução do peixe-lanterna</span>
</span></span><span class="line"><span class="cl"><span class="n">reproduce</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">fish</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">80</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condição de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">fish</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Reduzir contadores biológicos</span>
</span></span><span class="line"><span class="cl">  <span class="n">fish</span> <span class="o">&lt;-</span> <span class="n">fish</span> <span class="o">-</span> <span class="m">1L</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar novos peixes e reiniciar contadores</span>
</span></span><span class="line"><span class="cl">  <span class="n">fish</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">fish</span><span class="p">,</span> <span class="nf">rep_len</span><span class="p">(</span><span class="m">8L</span><span class="p">,</span> <span class="nf">length</span><span class="p">(</span><span class="n">fish[fish</span> <span class="o">==</span> <span class="m">-1L</span><span class="n">]</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="n">fish[fish</span> <span class="o">==</span> <span class="m">-1L</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="m">6L</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Recursão</span>
</span></span><span class="line"><span class="cl">  <span class="nf">reproduce</span><span class="p">(</span><span class="n">fish</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler uma lista de peixes e reproduzir por 80 dias</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/06a_lanternfish.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">reproduce</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 362666</span></span></span></code></pre></div><h2 id="peixes-lanterna-b">Peixes-lanterna (B)</h2>
<p>O segundo item do exercício não mudava essencialmente nada em relação ao
primeiro. Assumindo espaço e recursos infinitos, quantos peixes teríamos depois
de 256 dias?</p>
<p>Para resolver esse item, em teoria, seria necessário trocar apenas o valor do
<code>n</code> por 256. Mas não foi o que aconteceu&hellip; Por causa da ineficiência do
algoritmo, obter uma resposta demoraria horas e acabaria com a memória do meu
computador. Foi necessário pensar em um novo método de resolver o problema.</p>
<p>A solução abaixo foi inspirada pela função <code>table()</code>. Para reduzir a exigência
de espaço e não precisar iterar ao longo de um vetor com todos os peixes, eu
agrupei os peixes com o mesmo contador biológico em apenas uma linha de uma
tabela! Assim o programa nunca precisava lidar com mais de 9 linhas por dia,
resolvendo as complicações com espaço e tempo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Rodar n cíclos de reprodução do peixe-lanterna</span>
</span></span><span class="line"><span class="cl"><span class="n">reproduce</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">fish</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">80</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condição de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">fish</span><span class="o">$</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Reduzir contadores biológicos</span>
</span></span><span class="line"><span class="cl">  <span class="n">fish</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">fish</span><span class="p">,</span> <span class="n">timer</span> <span class="o">=</span> <span class="n">timer</span> <span class="o">-</span> <span class="m">1L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar novos peixes</span>
</span></span><span class="line"><span class="cl">  <span class="n">babies</span> <span class="o">&lt;-</span> <span class="n">fish</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">timer</span> <span class="o">==</span> <span class="m">-1L</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">timer</span> <span class="o">=</span> <span class="m">8L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Reiniciar contadores e recursão</span>
</span></span><span class="line"><span class="cl">  <span class="n">fish</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">babies</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">timer</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">timer</span> <span class="o">==</span> <span class="m">-1L</span><span class="p">,</span> <span class="m">6L</span><span class="p">,</span> <span class="n">timer</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">timer</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">reproduce</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler uma lista de peixes e reproduzir por 256 dias</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/06b_lanternfish.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;timer&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">count</span><span class="p">(</span><span class="n">timer</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">reproduce</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="m">256</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">format</span><span class="p">(</span><span class="n">scientific</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1640526601595</span></span></span></code></pre></div><h2 id="a-traição-das-baleias-a">A Traição das Baleias (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/7">dia 7</a> do AoC foi o mais rápido até
agora. A nossa tarefa era determinar a posição horizontal na qual um exército de
caranguejos deveria se alinhar, com a restrição de que deveríamos encontrar a
posição que exigisse menos combustível.</p>
<p>Cada caranguejo estava equipado de um mini-submarino que gastava 1 unidade de
combustível por unidade de deslocamento, logo o total de combustível gasto pela
tropa para ir até a posição <code>x</code> seria simplesmente <code>sum(abs(positions - x))</code>. A
saída era o combustível gasto para levar todos os caranguejos até a posição
mais econômica.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler vetor de posições iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">positions</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/07a_the_treachery_of_whales.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar nas posições para encontrar a mais barata</span>
</span></span><span class="line"><span class="cl"><span class="n">cheapest</span> <span class="o">&lt;-</span> <span class="kc">Inf</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">pos</span> <span class="kr">in</span> <span class="nf">max</span><span class="p">(</span><span class="n">positions</span><span class="p">)</span><span class="o">:</span><span class="nf">min</span><span class="p">(</span><span class="n">positions</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Calcular o combustível gasto para a posição</span>
</span></span><span class="line"><span class="cl">  <span class="n">fuel</span> <span class="o">&lt;-</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">positions</span> <span class="o">-</span> <span class="n">pos</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Trocar a resposta se essa posição for mais econômica</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">fuel</span> <span class="o">&lt;</span> <span class="n">cheapest</span><span class="p">)</span> <span class="n">cheapest</span> <span class="o">&lt;-</span> <span class="n">fuel</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="n">cheapest</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 328318</span></span></span></code></pre></div><p>Note que não era necessário testar nenhuma posição fora do intervalo
<code>max(positions):min(positions)</code>! Qualquer posição fora disso seria menos
econômica do que a ponta mais próxima a ela dentro do intervalo.</p>
<h2 id="a-traição-das-baleias-b">A Traição das Baleias (B)</h2>
<p>O segundo item mantinha o mesmo problema, mas mudava o cálculo do gasto de
combustível dos mini-submarinos: o primeiro movimento consumiria 1 unidade de
combustível, o segundo consumiria 2 unidades, o terceiro consumiria 3 e assim
por diante.</p>
<p>A única linha que muda dessa solução para a anterior é a que calcula o gasto
de combustível para cada posição. Se um caranguejo estiver na posição <code>a</code> e
quiser ir até a <code>x</code>, o seu consumo total será


<math display="inline"><mrow><msubsup><mo movablelimits="false">∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mrow><mi>|</mi><mi>a</mi><mo>−</mo><mi>x</mi><mi>|</mi></mrow></msubsup><mi>k</mi></mrow></math>
. Abaixo
a operação <code>sum(purrr::map_int(positions, ~sum(0:abs(.x - pos))))</code> faz isso para
todos os caranguejos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Iterar nas posições para encontrar a mais barata</span>
</span></span><span class="line"><span class="cl"><span class="n">cheapest</span> <span class="o">&lt;-</span> <span class="kc">Inf</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">pos</span> <span class="kr">in</span> <span class="nf">max</span><span class="p">(</span><span class="n">positions</span><span class="p">)</span><span class="o">:</span><span class="nf">min</span><span class="p">(</span><span class="n">positions</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Calcular o combustível gasto para a posição</span>
</span></span><span class="line"><span class="cl">  <span class="n">fuel</span> <span class="o">&lt;-</span> <span class="nf">sum</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="nf">map_int</span><span class="p">(</span><span class="n">positions</span><span class="p">,</span> <span class="o">~</span><span class="nf">sum</span><span class="p">(</span><span class="m">0</span><span class="o">:</span><span class="nf">abs</span><span class="p">(</span><span class="n">.x</span> <span class="o">-</span> <span class="n">pos</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Trocar a resposta se essa posição for mais econômica</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">fuel</span> <span class="o">&lt;</span> <span class="n">cheapest</span><span class="p">)</span> <span class="n">cheapest</span> <span class="o">&lt;-</span> <span class="n">fuel</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="n">cheapest</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 328318</span></span></span></code></pre></div><h2 id="busca-em-sete-segmentos-a">Busca em Sete Segmentos (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/8">oitavo dia</a> do AoC foi bastante difícil
para mim. O problema começou pelo enunciado, que é longo e complexo, então
realmente recomendo ler a versão original além do resumo que trago abaixo.</p>
<p>Dito isso, vamos lá. O problema dizia respeito a
<a href="https://pt.wikipedia.org/wiki/Display_de_sete_segmentos">displays de sete segmentos</a>,
onde cada número é representado por um conjunto de segmentos acessos; de acordo
com o diagrama abaixo, vemos que 0 é representado por <code>abcefg</code>, 1 é <code>cf</code> e assim
por diante.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#   0:      1:      2:      3:      4:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  aaaa    ....    aaaa    aaaa    ....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b    c  .    c  .    c  .    c  b    c</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b    c  .    c  .    c  .    c  b    c</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  ....    ....    dddd    dddd    dddd</span>
</span></span><span class="line"><span class="cl"><span class="c1"># e    f  .    f  e    .  .    f  .    f</span>
</span></span><span class="line"><span class="cl"><span class="c1"># e    f  .    f  e    .  .    f  .    f</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  gggg    ....    gggg    gggg    ....</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#   5:      6:      7:      8:      9:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  aaaa    aaaa    aaaa    aaaa    aaaa</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b    .  b    .  .    c  b    c  b    c</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b    .  b    .  .    c  b    c  b    c</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  dddd    dddd    ....    dddd    dddd</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .    f  e    f  .    f  e    f  .    f</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .    f  e    f  .    f  e    f  .    f</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  gggg    gggg    ....    gggg    gggg</span></span></span></code></pre></div><p>O desafio é que, no nosso submarino, todo os displays estão com os fios
trocados e, para piorar, cada display tem um arranjo diferente. A entrada do
problema é uma série de linhas como a abaixo: como os 10 dígitos são
representados em um display específico (em qualquer ordem) e, depois da barra,
4 dígitos que precisamos decodificar.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab |</span>
</span></span><span class="line"><span class="cl"><span class="c1"># cdfeb fcadb cdfeb cdbaf</span></span></span></code></pre></div><p>Alguns dígitos são fáceis de identificar. Os números 1, 4, 7 e 8 usam números
únicos de segmentos, então é possível perceber que, quando <code>ab</code> acenderam, o
display estava tentando mostrar um 1. Seguindo a mesma lógica, <code>dab</code> é 7, <code>eafb</code>
é 4 e <code>acedgfb</code> é 8.</p>
<p>O objetivo do primeiro item do dia 08 era contar quantas vezes os dígitos 1, 4,
7 e 8 aparecem nas saídas que devemos decodificar (lado direito da barra). A
solução foi bem simples, pois bastou pivotar a tabela e filtrar as linhas que
tinham <code>stringr::str_length()</code> igual a 2, 3, 4, ou 7.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;data-raw/08a_seven_segment_search.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_delim</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="kc">NULL</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;P&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_pad</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s">&#34;left&#34;</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">)),</span> <span class="s">&#34;remove&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;V&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_pad</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s">&#34;left&#34;</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">remove</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">V01</span><span class="o">:</span><span class="n">V04</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">pivot_longer</span><span class="p">(</span><span class="n">V01</span><span class="o">:</span><span class="n">V04</span><span class="p">,</span> <span class="n">names_to</span> <span class="o">=</span> <span class="s">&#34;col&#34;</span><span class="p">,</span> <span class="n">values_to</span> <span class="o">=</span> <span class="s">&#34;value&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_length</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">7</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">nrow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 365</span></span></span></code></pre></div><h2 id="busca-em-sete-segmentos-b">Busca em Sete Segmentos (B)</h2>
<p>O verdadeiro problema veio no item 2. Aqui o exercício abandona qualquer
pretexto de bondade e pede de uma vez para decodificarmos os dígitos depois da
barra baseados nos 10 padrões antes da barra. A saída deveria ser a soma de
todos os números de 4 dígitos decodificados.</p>
<p>Minha primeira tentativa de resolver o problema testava cada segmento em cada
posição (essencialmente verificando todos os possíveis jeitos de embaralhar os
fios) para ver em qual das configurações os padrões faziam sentido; depois seria
só bater os padrões com os 4 dígitos da direita para ver quem é quem. Não
preciso nem dizer que isso seria demorado demais para funcionar.</p>
<p>Depois de um tempo olhando para o arquivo de entrada, entretanto, me veio uma
luz: talvez eu pudesse analisar a <em>frequência</em> com a qual cada segmento aparece
nos padrões. Perceba, por exemplo, que no diagrama acima o segmento <code>e</code> está
ligado em 4 dígitos (0, 2, 6 e 8). O fato importante é que ele é o único
segmento com essa propriedade!</p>
<p>Partindo deste princípio, criei as seguinte regras para o código:</p>
<ol>
<li>
<p>O único segmento que aparecer 4 vezes nos padrões corresponderá ao <code>e</code>;</p>
</li>
<li>
<p>O único segmento que aparecer 6 vezes nos padrões corresponderá ao <code>b</code>;</p>
</li>
<li>
<p>O único segmento que aparecer 9 vezes nos padrões corresponderá ao <code>f</code>;</p>
</li>
<li>
<p>No padrão com 2 segmentos acessos, aquele que não representar o <code>e</code>
corresponderá ao <code>c</code> (número 1).</p>
</li>
<li>
<p>No padrão com 3 segmentos acessos, aquele que não representar <code>c</code> ou <code>f</code>
corresponderá ao <code>a</code> (número 7).</p>
</li>
<li>
<p>No padrão com 4 segmentos acessos, aquele que não representar <code>b</code>, <code>c</code> ou <code>f</code>
corresponderá ao <code>d</code> (número 4).</p>
</li>
<li>
<p>O segmento que ainda não tiver correspondente corresponderá ao <code>g</code>.</p>
</li>
</ol>
<p>O resto do código cuidava de organizar as letras de cada dígito de modo que
fosse fácil transpor as correspondências dos 10 padrões para os 4 valores das
saídas.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Decodificar uma linha da entrada</span>
</span></span><span class="line"><span class="cl"><span class="n">decode</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontra e quebra o padrão que tenha certa str_length()</span>
</span></span><span class="line"><span class="cl">  <span class="n">find_by_len</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">patterns</span><span class="p">,</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">patterns</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">magrittr</span><span class="o">::</span><span class="nf">extract</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_length</span><span class="p">(</span><span class="n">patterns</span><span class="p">)</span> <span class="o">==</span> <span class="n">len</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Frequências de referência</span>
</span></span><span class="line"><span class="cl">  <span class="n">ref_freq</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;a&#34;</span> <span class="o">=</span> <span class="m">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;b&#34;</span> <span class="o">=</span> <span class="m">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;c&#34;</span> <span class="o">=</span> <span class="m">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;d&#34;</span> <span class="o">=</span> <span class="m">7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;e&#34;</span> <span class="o">=</span> <span class="m">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;f&#34;</span> <span class="o">=</span> <span class="m">9</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;g&#34;</span> <span class="o">=</span> <span class="m">7</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Valores de referência</span>
</span></span><span class="line"><span class="cl">  <span class="n">ref_val</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;abdefg&#34;</span> <span class="o">=</span> <span class="m">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;abcefg&#34;</span> <span class="o">=</span> <span class="m">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;cf&#34;</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;acdfg&#34;</span> <span class="o">=</span> <span class="m">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;abcdfg&#34;</span> <span class="o">=</span> <span class="m">9</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;abcdefg&#34;</span> <span class="o">=</span> <span class="m">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;bcdf&#34;</span> <span class="o">=</span> <span class="m">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;acf&#34;</span> <span class="o">=</span> <span class="m">7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;abdfg&#34;</span> <span class="o">=</span> <span class="m">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;acdeg&#34;</span> <span class="o">=</span> <span class="m">2</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Calcular frequências desta entrada</span>
</span></span><span class="line"><span class="cl">  <span class="n">cur_freq</span> <span class="o">&lt;-</span> <span class="n">entry</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">P01</span><span class="o">:</span><span class="n">P10</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">table</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar um dicionário para traduzir os segmentos</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Traduzir segmentos com frequências únicas</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;e&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="nf">names</span><span class="p">(</span><span class="n">cur_freq[cur_freq</span> <span class="o">==</span> <span class="m">4</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;b&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="nf">names</span><span class="p">(</span><span class="n">cur_freq[cur_freq</span> <span class="o">==</span> <span class="m">6</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;f&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="nf">names</span><span class="p">(</span><span class="n">cur_freq[cur_freq</span> <span class="o">==</span> <span class="m">9</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Extrair padrões da entrada</span>
</span></span><span class="line"><span class="cl">  <span class="n">patterns</span> <span class="o">&lt;-</span> <span class="n">entry</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">P01</span><span class="o">:</span><span class="n">P10</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Determinar segmento que falta do 1</span>
</span></span><span class="line"><span class="cl">  <span class="n">one</span> <span class="o">&lt;-</span> <span class="nf">find_by_len</span><span class="p">(</span><span class="n">patterns</span><span class="p">,</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;c&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="n">one[</span><span class="o">!</span><span class="n">one</span> <span class="o">%in%</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Determinar segmento que falta do 7</span>
</span></span><span class="line"><span class="cl">  <span class="n">seven</span> <span class="o">&lt;-</span> <span class="nf">find_by_len</span><span class="p">(</span><span class="n">patterns</span><span class="p">,</span> <span class="m">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;a&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="n">seven[</span><span class="o">!</span><span class="n">seven</span> <span class="o">%in%</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Determinar segmento que falta do 4</span>
</span></span><span class="line"><span class="cl">  <span class="n">four</span> <span class="o">&lt;-</span> <span class="nf">find_by_len</span><span class="p">(</span><span class="n">patterns</span><span class="p">,</span> <span class="m">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;d&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="n">four[</span><span class="o">!</span><span class="n">four</span> <span class="o">%in%</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Determinar último segmento que falta</span>
</span></span><span class="line"><span class="cl">  <span class="n">dict[[</span><span class="s">&#34;g&#34;</span><span class="n">]]</span> <span class="o">&lt;-</span> <span class="nf">names</span><span class="p">(</span><span class="n">cur_freq</span><span class="p">)</span><span class="n">[</span><span class="o">!</span><span class="nf">names</span><span class="p">(</span><span class="n">cur_freq</span><span class="p">)</span> <span class="o">%in%</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Traduzir segmentos dos valores de saída</span>
</span></span><span class="line"><span class="cl">  <span class="n">entry</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">V01</span><span class="o">:</span><span class="n">V04</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">names</span><span class="p">(</span><span class="n">dict</span><span class="p">)</span><span class="nf">[match</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="n">dict</span><span class="p">)</span><span class="n">]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">sort</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="n">str_c</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">(</span><span class="n">ref_val</span><span class="p">)</span><span class="nf">[match</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="nf">names</span><span class="p">(</span><span class="n">ref_val</span><span class="p">))</span><span class="n">]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.integer</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler entrada, mapear decode() e somar todas os valores de saída</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/08b_seven_segment_search.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_delim</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="kc">NULL</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;P&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_pad</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s">&#34;left&#34;</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">)),</span> <span class="s">&#34;remove&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;V&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_pad</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="s">&#34;left&#34;</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">remove</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">rowid_to_column</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">nest</span><span class="p">(</span><span class="n">entry</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="n">P01</span><span class="o">:</span><span class="n">V04</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">output</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map_dbl</span><span class="p">(</span><span class="n">entry</span><span class="p">,</span> <span class="n">decode</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">output</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">output</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 975706</span></span></span></code></pre></div><h2 id="bacia-de-fumaça-a">Bacia de Fumaça (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/9">dia 9</a> do AoC foi desafiador, apesar de
não tanto quanto o anterior. Como sempre o problema envolvia uma historinha que
não contribui muito para o entendimento do enunciado, então vamos direto ao
ponto: recebemos uma matriz 100x100 que representa um mapa de alturas e
precisávamos encontrar todos os pontos que eram cercados (em cima, embaixo, na
esquerda e na direita) por pontos mais altos. Ademais sabíamos que as alturas
iam de 0 a 9 e que as fronteiras fora do mapa podiam ser todas consideradas mais
altas que o resto do mapa. A resposta do problema seria o risco total de todos
os pontos baixos, onde o risco de um ponto é igual à sua altura + 1.</p>
<p>O problema não é tão complicado, pois bastaria iterar em todos os pontos da
matriz e comparar cada um com seus vizinhos. O maior dezafio era lidar com as
fronteiras do mapa. Para isso, resolvi cercar toda a matriz por noves e iterar
no quadrado 2:101x2:101.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler o mapa de alturas e estofar as fronteiras com 9</span>
</span></span><span class="line"><span class="cl"><span class="n">height</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/09a_smoke_basin.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">matrix</span><span class="p">(</span><span class="n">nrow</span> <span class="o">=</span> <span class="m">100</span><span class="p">,</span> <span class="n">ncol</span> <span class="o">=</span> <span class="m">100</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">9</span><span class="p">,</span> <span class="m">100</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="nf">rbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">9</span><span class="p">,</span> <span class="m">100</span><span class="p">),</span> <span class="n">m</span><span class="p">)}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">9</span><span class="p">,</span> <span class="m">102</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="nf">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">9</span><span class="p">,</span> <span class="m">102</span><span class="p">),</span> <span class="n">m</span><span class="p">)}()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar por todos os pontos</span>
</span></span><span class="line"><span class="cl"><span class="n">risk</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Verificar se é um ponto baixo e somar o risco ao total</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">height[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;</span> <span class="n">height[i</span> <span class="o">-</span> <span class="m">1</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">      <span class="n">height[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;</span> <span class="n">height[i</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">      <span class="n">height[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;</span> <span class="n">height[i</span><span class="p">,</span> <span class="n">j</span> <span class="o">-</span> <span class="m">1</span><span class="n">]</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">      <span class="n">height[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;</span> <span class="n">height[i</span><span class="p">,</span> <span class="n">j</span> <span class="o">+</span> <span class="m">1</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">risk</span> <span class="o">&lt;-</span> <span class="n">risk</span> <span class="o">+</span> <span class="n">height[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="n">risk</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 494</span></span></span></code></pre></div><h2 id="bacia-de-fumaça-b">Bacia de Fumaça (B)</h2>
<p>O segundo item já era mais complicado. Considerando que os pontos com altura 9
não pertencem a nenhuma bacia, precisávamos encontrar as 3 maiores bacias no
nosso mapa. Uma bacia é definida por toda uma região cercada por noves e seu
tamanho é igual ao número de pontos contíguos contidos nessa área.</p>
<p>O diagrama abaixo não estava no enunciado, mas ele me ajudou muito a entender o
que era uma bacia. Para criá-lo, eu peguei um retângulo na ponta do meu mapa e
substituí todos os números menores que 9 por um <code>.</code>, representando assim as
bacias. Cada região cercada por noves é uma bacia diferente.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># ....999.........9.9....99......9....9..........9</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...9.9.9.......9...9..9.......9.9...99.99.9.....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..9.....9.9.....9...99...........999.999.9.9....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..9......9.9...9....999.........9..9..9.....999.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 99..........999......9999......9..9..9.....9...9</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........9..9........99...9.9.......9.........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 9..............9...9..9..9.99.9......9..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........99.9...9.99....9..99.....9...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ............99....9..9.......9.......9..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 9........99999...9....9.9....9.......999........</span></span></span></code></pre></div><p>Minha solução começou igual à do item anterior, mas desta vez criei também uma
tabela com todos os pontos do mapa. Meu objetivo era fazer uma
<a href="https://pt.wikipedia.org/wiki/Busca_em_largura">busca em largura</a> e remover
desta tabela os pontos já explorados.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar uma tabela de pontos a explorar</span>
</span></span><span class="line"><span class="cl"><span class="n">points</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">cross2</span><span class="p">(</span><span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">,</span> <span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_int</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">transpose</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;i&#34;</span><span class="p">,</span> <span class="s">&#34;j&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">))</span></span></span></code></pre></div><p>A seguir eu criei uma função que explorava uma bacia a partir de um ponto
&ldquo;semente&rdquo;. O primeiro passo era verificar se o ponto já tinha sido explorado e
retornar 0 se sim (indicando que aquele ponto não contribuiria mais para o
tamanho da bacia). Se o ponto não tivesse sido explorado, então o código o
removia da tabela de pontos e verificava se ele tinha altura 9, mais uma vez
retornando 0 se sim. O final da função aplicava uma recursão nos 4 vizinhos do
ponto, somando os tamanhos das 4 sub-bacias encontradas mais 1 (indicando que o
ponto &ldquo;semente&rdquo; contribuia em 1 para o tamanho total da bacia).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Explorar uma bacia</span>
</span></span><span class="line"><span class="cl"><span class="n">explore</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pular se o ponto já tiver sido explorado</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">i</span> <span class="o">==</span> <span class="n">a</span><span class="p">,</span> <span class="n">j</span> <span class="o">==</span> <span class="n">b</span><span class="p">))</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Marcar o ponto como explorado</span>
</span></span><span class="line"><span class="cl">  <span class="n">points</span> <span class="o">&lt;&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">a</span> <span class="o">|</span> <span class="n">j</span> <span class="o">!=</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Se a altura for 9, então ele não faz parte da bacia</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">height[a</span><span class="p">,</span> <span class="n">b]</span> <span class="o">==</span> <span class="m">9</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar os pontos vizinhos à bacia</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nf">explore</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="m">1</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">explore</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">explore</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">explore</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>A resposta para o item era o produto dos tamanhos das 3 maiores bacias do mapa,
então o programa terminava iterando na matriz, calculando o tamanho de todas as
bacias e seguindo para obter o resultado final.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Iterar por todos os pontos</span>
</span></span><span class="line"><span class="cl"><span class="n">basins</span> <span class="o">&lt;-</span> <span class="nf">matrix</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">10404</span><span class="p">),</span> <span class="m">102</span><span class="p">,</span> <span class="m">102</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="m">101</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">basins[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;-</span> <span class="nf">explore</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Multiplicar as 3 maiores bacias</span>
</span></span><span class="line"><span class="cl"><span class="n">basins</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sort</span><span class="p">(</span><span class="n">decreasing</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">magrittr</span><span class="o">::</span><span class="nf">extract</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">prod</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1048128</span></span></span></code></pre></div><h2 id="pontuação-de-sintaxe-a">Pontuação de Sintaxe (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/10">dia 10</a> do AoC pedia para que
resolvessemos um clássico problema de parentização com alguns facilitadores. Em
resumo, recebíamos uma string composta por parênteses e seus amigos (&quot;(&quot;, &ldquo;[&rdquo;,
&ldquo;{&rdquo;, &ldquo;&lt;&rdquo;, &ldquo;&gt;&rdquo;, &ldquo;}&rdquo;, &ldquo;]&rdquo;, &ldquo;)&rdquo;) e precisávamos identificar se o fechamento de
algum deles estava errado, por exemplo, &ldquo;[}&rdquo;, &ldquo;{()()()&gt;&rdquo;, etc. Para cada string
que tivesse um fechamento ilegal recebia uma quantidade de pontos de acordo com
a tabela abaixo e, finalmente, a saída do exercício era a soma de todas as
pontuações.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># ): 3 pontos.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ]: 57 pontos.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># }: 1197 pontos.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &gt;: 25137 pontos.</span></span></span></code></pre></div><p>Para quem nunca viu um problema desse tipo, a solução pode ser alcançada
facilmente usando uma
<a href="https://pt.wikipedia.org/wiki/Pilha_(inform%C3%A1tica)">pilha</a>. Cada caractere
que abre um bloco é colocado na pilha e, para cada caractere que fecha um bloco,
removemos o elemento do topo da pilha. Se os caracteres se complementam
corretamente o algoritmo segue em frente, caso contrário ele busca a pontuação
na tabela e retorna.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Correspondência de valores</span>
</span></span><span class="line"><span class="cl"><span class="n">scores</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;)&#34;</span> <span class="o">=</span> <span class="m">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;]&#34;</span> <span class="o">=</span> <span class="m">57</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;}&#34;</span> <span class="o">=</span> <span class="m">1197</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;&gt;&#34;</span> <span class="o">=</span> <span class="m">25137</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Calcular a pontuação por caractere ilegal em uma linha</span>
</span></span><span class="line"><span class="cl"><span class="n">score_ilegal</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">stack</span> <span class="o">&lt;-</span> <span class="n">flifo</span><span class="o">::</span><span class="nf">lifo</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar na linha até um elemento não corresponder</span>
</span></span><span class="line"><span class="cl">  <span class="n">symbols</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span><span class="n">[[1]]</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">symbol</span> <span class="kr">in</span> <span class="n">symbols</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Empilhar ou desempilhar (e calcular pontuação se necessário)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">symbol</span> <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;(&#34;</span><span class="p">,</span> <span class="s">&#34;[&#34;</span><span class="p">,</span> <span class="s">&#34;{&#34;</span><span class="p">,</span> <span class="s">&#34;&lt;&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flifo</span><span class="o">::</span><span class="nf">push</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">symbol</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">check</span> <span class="o">&lt;-</span> <span class="n">flifo</span><span class="o">::</span><span class="nf">pop</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="kr">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">check</span> <span class="o">==</span> <span class="s">&#34;{&#34;</span> <span class="o">&amp;&amp;</span> <span class="n">symbol</span> <span class="o">!=</span> <span class="s">&#34;}&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">check</span> <span class="o">==</span> <span class="s">&#34;(&#34;</span> <span class="o">&amp;&amp;</span> <span class="n">symbol</span> <span class="o">!=</span> <span class="s">&#34;)&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">check</span> <span class="o">==</span> <span class="s">&#34;[&#34;</span> <span class="o">&amp;&amp;</span> <span class="n">symbol</span> <span class="o">!=</span> <span class="s">&#34;]&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">check</span> <span class="o">==</span> <span class="s">&#34;&lt;&#34;</span> <span class="o">&amp;&amp;</span> <span class="n">symbol</span> <span class="o">!=</span> <span class="s">&#34;&gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">return</span><span class="p">(</span><span class="n">scores</span><span class="nf">[names</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span> <span class="o">==</span> <span class="n">symbol][[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar nas linhas e calcular pontuações</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/10a_syntax_scoring.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map_dbl</span><span class="p">(</span><span class="n">score_ilegal</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 216297</span></span></span></code></pre></div><h2 id="pontuação-de-sintaxe-b">Pontuação de Sintaxe (B)</h2>
<p>O segundo item do problema pedia para que começássemos removendo as linhas que
tinham pontuação maior que 0 (então só foi necessário filtrar isso no código,
que vou omitir). Depois disso o objetivo era completar as linhas que restavam.</p>
<p>O fato é que as linhas restantes estavam todas com um pedaço faltando, por
exemplo, &ldquo;[({(&lt;(())[]&gt;[[{[]{&lt;()&lt;&raquo;&rdquo; precisa ainda de &ldquo;}}]])})]&rdquo; para ficar
correta. Usando a lógica do item anterior, só precisávamos seguir o mesmo
roteiro e, ao final da linha, contar os pontos dos caracteres que ainda haviam
sobrado na pilha.</p>
<p>Desta vez a regra de pontuação era diferente: para cada caractere faltante,
precisávamos multiplicar a pontuação corrente por 5 e então somar o valor do
caractere de acordo com uma nova tabelha. A resposta final era a mediana da
pontuação de todoas as linhas. Enfim, o código vai a seguir:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler linhas e remover corrompidas</span>
</span></span><span class="line"><span class="cl"><span class="n">lines</span> <span class="o">&lt;-</span> <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="s">&#34;data-raw/10b_syntax_scoring.txt&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">lines</span> <span class="o">&lt;-</span> <span class="n">lines[purrr</span><span class="o">::</span><span class="nf">map_dbl</span><span class="p">(</span><span class="n">lines</span><span class="p">,</span> <span class="n">score_ilegal</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Correspondência de valores</span>
</span></span><span class="line"><span class="cl"><span class="n">scores</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;(&#34;</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;[&#34;</span> <span class="o">=</span> <span class="m">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;{&#34;</span> <span class="o">=</span> <span class="m">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;&lt;&#34;</span> <span class="o">=</span> <span class="m">4</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Calcular a pontuação por caractere faltante em uma linha</span>
</span></span><span class="line"><span class="cl"><span class="n">score_complete</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">stack</span> <span class="o">&lt;-</span> <span class="n">flifo</span><span class="o">::</span><span class="nf">lifo</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar na linha e remover parte completa</span>
</span></span><span class="line"><span class="cl">  <span class="n">symbols</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span><span class="n">[[1]]</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">symbol</span> <span class="kr">in</span> <span class="n">symbols</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Empilhar ou desempilhar</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">symbol</span> <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;(&#34;</span><span class="p">,</span> <span class="s">&#34;[&#34;</span><span class="p">,</span> <span class="s">&#34;{&#34;</span><span class="p">,</span> <span class="s">&#34;&lt;&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flifo</span><span class="o">::</span><span class="nf">push</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">symbol</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flifo</span><span class="o">::</span><span class="nf">pop</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar no resto da pilha e calcular pontos</span>
</span></span><span class="line"><span class="cl">  <span class="n">score</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">flifo</span><span class="o">::</span><span class="nf">size</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">check</span> <span class="o">&lt;-</span> <span class="n">flifo</span><span class="o">::</span><span class="nf">pop</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">score</span> <span class="o">&lt;-</span> <span class="p">(</span><span class="n">score</span> <span class="o">*</span> <span class="m">5</span><span class="p">)</span> <span class="o">+</span> <span class="n">scores</span><span class="nf">[names</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span> <span class="o">==</span> <span class="n">check][[1]]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">score</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar mediana das pontuações</span>
</span></span><span class="line"><span class="cl"><span class="n">lines</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map_dbl</span><span class="p">(</span><span class="n">score_complete</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">median</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2165057169</span></span></span></code></pre></div><h2 id="polvo-dumbo-a">Polvo-dumbo (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/11">dia 11</a> do AoC foi bastante complicado
e o meu código talvez tenha ficado pior ainda. As instruções eram até simples:
recebemos uma matriz 10x10 com os níveis de energia de 100
<a href="https://pt.wikipedia.org/wiki/Grimpoteuthis">polvos-dumbo</a> e precisávamos
acompanhar seus níveis de energia ao longo de 100 iterações. As regras eram as
seguintes:</p>
<ul>
<li>
<p>Primeiro, o nível de energia de cada polvo sobe em 1.</p>
</li>
<li>
<p>Depois, qualquer polvo com nível de energia maior que 9 emite luz (pisca).
Isso aumenta o nível de energia de todos os polvos adjacentes em 1, incluindo os
adjacentes diagonalmente. Se isso causar um polvo a atingir um nível de energia
maior que 9, ele também pisca. Esse processo continua conforme mais polvos
passam do nível de energia 9. Um polvo só pode piscar uma vez por passo e não
pode subir mais nenhum nível de energia a partir daí.</p>
</li>
<li>
<p>Finalmente, todos os polvos que piscaram durante este passo têm seus níveis de
energia ajustados para 0 (já que ele usou toda a sua energia para piscar).</p>
</li>
</ul>
<p>Meu código seguia esse procedimento à risca e precisou de 3 loops aninhados para
funcionar. O truque mais importante foi criar um clone dos polvos que marcava
todos os polvos que já tinham piscado para garantir que nenhum deles ganharia
mais energia durante aquele passo; este mecanismo envolvia marcar um polvo que
piscava com 0 e um polvo que tinha piscado em qualquer ponto anterior do loop
com -1 (para que ele não fosse contado duas vezes). O resultado final deveria
ser o número de piscadas totais depois dos 100 passos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler matriz</span>
</span></span><span class="line"><span class="cl"><span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/11a_dumbo_octopus.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">X1</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;C&#34;</span><span class="p">,</span> <span class="m">0</span><span class="o">:</span><span class="m">10</span><span class="p">),</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">C0</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">as.numeric</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.matrix</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar nos 100 passos</span>
</span></span><span class="line"><span class="cl"><span class="n">flashes</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">k</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">100</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aumentar níveis de energia</span>
</span></span><span class="line"><span class="cl">  <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="p">(</span><span class="n">dumbo</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span> <span class="o">%%</span> <span class="m">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar energia aos polvos cujos vizinhos piscaram</span>
</span></span><span class="line"><span class="cl">  <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">FALSE</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span><span class="p">(</span><span class="o">!</span><span class="n">flag</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Contar piscadas</span>
</span></span><span class="line"><span class="cl">    <span class="n">flashes</span> <span class="o">&lt;-</span> <span class="n">flashes</span> <span class="o">+</span> <span class="nf">sum</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Adicionar energia aos polvos adjacentes a piscadas</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo_</span> <span class="o">&lt;-</span> <span class="n">dumbo</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Índices dos vizinhos</span>
</span></span><span class="line"><span class="cl">        <span class="n">i1</span> <span class="o">&lt;-</span> <span class="n">i</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="n">i2</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">j1</span> <span class="o">&lt;-</span> <span class="n">j</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="n">j2</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Adicionar energia nos índices (exceto no centro)</span>
</span></span><span class="line"><span class="cl">        <span class="kr">if</span> <span class="p">(</span><span class="n">dumbo[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">dumbo_[i1</span><span class="o">:</span><span class="n">i2</span><span class="p">,</span> <span class="n">j1</span><span class="o">:</span><span class="n">j2]</span> <span class="o">&lt;-</span> <span class="n">dumbo_[i1</span><span class="o">:</span><span class="n">i2</span><span class="p">,</span> <span class="n">j1</span><span class="o">:</span><span class="n">j2]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">          <span class="n">dumbo_[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;-</span> <span class="n">dumbo_[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Separar piscadas anteriores dos que piscaram na última iteração</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Sobrescrever as piscadas com 0 (eles não podem receber mais energia)</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo_</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Verificar se o passo atual acabou</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">any</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">&gt;</span> <span class="m">9</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">TRUE</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Prevenir piscadas antigas de serem contadas de novo</span>
</span></span><span class="line"><span class="cl">      <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">&gt;</span> <span class="m">9</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="n">flashes</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1681</span></span></span></code></pre></div><h2 id="polvo-dumbo-b">Polvo-dumbo (B)</h2>
<p>Felizmente o segundo item o exercício de hoje foi bem mais simples.
Eventualmente todos os polvos entram em sincronia, ou seja, passam a piscar
todos juntos; o nosso objetivo era descobrir em que passo isso acontecia. A
única coisa que precisei fazer com o código do item anterior foi ignorar o
limite de passos e criar uma verificação para quando todos os polvos atingiam 0
de energia juntos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler matriz</span>
</span></span><span class="line"><span class="cl"><span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/11b_dumbo_octopus.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">X1</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;C&#34;</span><span class="p">,</span> <span class="m">0</span><span class="o">:</span><span class="m">10</span><span class="p">),</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">C0</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">as.numeric</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.matrix</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar em 1000 passos</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">k</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">1000</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">print</span><span class="p">(</span><span class="n">k</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aumentar níveis de energia</span>
</span></span><span class="line"><span class="cl">  <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="p">(</span><span class="n">dumbo</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span> <span class="o">%%</span> <span class="m">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar energia aos polvos cujos vizinhos piscaram</span>
</span></span><span class="line"><span class="cl">  <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">FALSE</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span><span class="p">(</span><span class="o">!</span><span class="n">flag</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Adicionar energia aos polvos adjacentes a piscadas</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo_</span> <span class="o">&lt;-</span> <span class="n">dumbo</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Índices dos vizinhos</span>
</span></span><span class="line"><span class="cl">        <span class="n">i1</span> <span class="o">&lt;-</span> <span class="n">i</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="n">i2</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">j1</span> <span class="o">&lt;-</span> <span class="n">j</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="n">j2</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Adicionar energia nos índices (exceto no centro)</span>
</span></span><span class="line"><span class="cl">        <span class="kr">if</span> <span class="p">(</span><span class="n">dumbo[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">dumbo_[i1</span><span class="o">:</span><span class="n">i2</span><span class="p">,</span> <span class="n">j1</span><span class="o">:</span><span class="n">j2]</span> <span class="o">&lt;-</span> <span class="n">dumbo_[i1</span><span class="o">:</span><span class="n">i2</span><span class="p">,</span> <span class="n">j1</span><span class="o">:</span><span class="n">j2]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">          <span class="n">dumbo_[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;-</span> <span class="n">dumbo_[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Separar piscadas anteriores dos que piscaram na última iteração</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Sobrescrever as piscadas com 0 (eles não podem receber mais energia)</span>
</span></span><span class="line"><span class="cl">    <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo_</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Verificar se o passo atual acabou</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">any</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">&gt;</span> <span class="m">9</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">TRUE</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Prevenir piscadas antigas de serem contadas de novo</span>
</span></span><span class="line"><span class="cl">      <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">==</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">dumbo</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">&gt;</span> <span class="m">9</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dumbo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Parar se todos os polvos tiverem piscado</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">all</span><span class="p">(</span><span class="n">dumbo</span> <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">break</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="n">k</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 276</span></span></span></code></pre></div><h2 id="busca-de-caminho-a">Busca de Caminho (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/12">dia 12</a>, juntamente com os anteriores,
começou a me deixar preocupado com os próximos exercícios do Advent of Code.
Aparentemente a dificuldade vai aumentando conforme o passar dos dias, mas já
estou chegando no limite do meu conhecimento.</p>
<p>Mais uma vez temos um enunciado complicado, então leia a versão original se
ficar difícil de entender aqui. Nosso objetivo esta vez era contar o número de
caminhos que o nosso submarino podia tomar em um sistema de cavernas.</p>
<p>A entrada era uma lista de arestas nomeadas em um grafo. Os nossos caminhos
deveriam sempre começar na caverna chamada &ldquo;start&rdquo; e terminar na chamada &ldquo;end&rdquo;,
sendo que todas as outras eram divididas em dois grupos: grandes e pequenas. Uma
caverna grande era demarcada por uma letra maiúscula e podia ser utilizada pelo
nosso caminho qualquer número de vezes. Já uma caverna pequena (demarcada por
uma letra minúscula), só podia ser utilizada uma vez no caminho.</p>
<p>Veja o exemplo abaixo. A primeira parte seria a entrada do problema, a segunda,
o diagrama das cavernas e a terceira, os 10 possíveis caminhos para o nosso
submarino.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># start-A</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start-b</span>
</span></span><span class="line"><span class="cl"><span class="c1"># A-c</span>
</span></span><span class="line"><span class="cl"><span class="c1"># A-b</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b-d</span>
</span></span><span class="line"><span class="cl"><span class="c1"># A-end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># b-end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#     start</span>
</span></span><span class="line"><span class="cl"><span class="c1">#     /   \</span>
</span></span><span class="line"><span class="cl"><span class="c1"># c--A-----b--d</span>
</span></span><span class="line"><span class="cl"><span class="c1">#     \   /</span>
</span></span><span class="line"><span class="cl"><span class="c1">#      end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,b,A,c,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,b,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,b,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,c,A,b,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,c,A,b,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,c,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,b,A,c,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,b,A,end</span>
</span></span><span class="line"><span class="cl"><span class="c1"># start,b,end</span></span></span></code></pre></div><p>Minha solução envolvia uma tabela que representava todas as arestas do grafo do
sistema de cavernas. A cada nova recursão, a última caverna poderia ser mantida
na tabela ou removida (no caso das cavernas pequenas); toda vez que um caminho
chegasse ao &ldquo;end&rdquo;, um contador global era incrementado.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Contar caminhos distintos em um grafo</span>
</span></span><span class="line"><span class="cl"><span class="n">count</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="n">count_paths</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="s">&#34;start&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Verificar se o nó atual é &#34;pequeno&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cave</span> <span class="o">&lt;-</span> <span class="nf">tail</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">is_small</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_to_lower</span><span class="p">(</span><span class="n">cave</span><span class="p">)</span> <span class="o">==</span> <span class="n">cave</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condições de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">cave</span> <span class="o">==</span> <span class="s">&#34;end&#34;</span><span class="p">)</span> <span class="p">{</span><span class="n">count</span> <span class="o">&lt;&lt;-</span> <span class="n">count</span> <span class="o">+</span> <span class="m">1</span><span class="p">;</span> <span class="kr">return</span><span class="p">(</span><span class="m">1</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">any</span><span class="p">(</span><span class="n">graph</span><span class="o">$</span><span class="n">orig</span> <span class="o">==</span> <span class="n">cave</span><span class="p">))</span> <span class="kr">return</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar próximo nó do caminho</span>
</span></span><span class="line"><span class="cl">  <span class="n">searches</span> <span class="o">&lt;-</span> <span class="n">graph</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">orig</span> <span class="o">==</span> <span class="n">cave</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">prepend</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar nós disponíveis</span>
</span></span><span class="line"><span class="cl">  <span class="n">graph</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="n">is_small</span><span class="p">)</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">orig</span> <span class="o">!=</span> <span class="n">cave</span><span class="p">)</span> <span class="kr">else</span> <span class="n">graph</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos possíveis caminhos</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">search</span> <span class="kr">in</span> <span class="n">searches</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">count_paths</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">search</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Retornar contador global</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler arestas do grafo e retornar conta dos caminhos</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/12a_passage_pathing.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;path&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;orig&#34;</span><span class="p">,</span> <span class="s">&#34;dest&#34;</span><span class="p">),</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="nf">rev</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">d</span><span class="p">))))}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">dest</span> <span class="o">!=</span> <span class="s">&#34;start&#34;</span><span class="p">,</span> <span class="n">orig</span> <span class="o">!=</span> <span class="s">&#34;end&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">count_paths</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 4792</span></span></span></code></pre></div><h2 id="busca-de-caminho-b">Busca de Caminho (B)</h2>
<p>O segundo item do problema mudava muito pouco o enunciado. Agora, ao invés de
cada caverna pequena poder ser visitada apenas 1 vez, tínhamos um pequeno
acréscimo de tempo. Isso queria dizer que, em cada caminho até o final do
sistema de cavernas, podíamos visitar <em>apenas 1</em> das cavernas pequenas até 2
vezes.</p>
<p>Minha solução foi criar um argumento chamado <code>boost</code> que indicava se já tínhamos
usado o nosso excedente de tempo naquele caminho expecífico. Se não tivéssemos,
poderíamos não retirar uma das cavernas pequenas da lista imediatamente. Esta
estratégia funcionou, mas gerou caminhos repetidos (usando e não usando o
<code>boost</code>), então, ao invés de contar os caminhos, passei a salvar os caminhos e
contar o número de caminhos distintos no final.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar todos os caminhos distintos em um grafo</span>
</span></span><span class="line"><span class="cl"><span class="n">all_paths</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">get_paths</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="s">&#34;start&#34;</span><span class="p">,</span> <span class="n">boost</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Verificar se o nó atual é &#34;pequeno&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cave</span> <span class="o">&lt;-</span> <span class="nf">tail</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">is_small</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_to_lower</span><span class="p">(</span><span class="n">cave</span><span class="p">)</span> <span class="o">==</span> <span class="n">cave</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condições de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">cave</span> <span class="o">==</span> <span class="s">&#34;end&#34;</span><span class="p">)</span> <span class="p">{</span><span class="n">all_paths</span> <span class="o">&lt;&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">all_paths</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="n">path</span><span class="p">));</span> <span class="kr">return</span><span class="p">(</span><span class="m">1</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">any</span><span class="p">(</span><span class="n">graph</span><span class="o">$</span><span class="n">orig</span> <span class="o">==</span> <span class="n">cave</span><span class="p">))</span> <span class="kr">return</span><span class="p">(</span><span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar próximo nó do caminho</span>
</span></span><span class="line"><span class="cl">  <span class="n">searches</span> <span class="o">&lt;-</span> <span class="n">graph</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">orig</span> <span class="o">==</span> <span class="n">cave</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">prepend</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar nós disponíveis</span>
</span></span><span class="line"><span class="cl">  <span class="n">graph_</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="n">is_small</span><span class="p">)</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">orig</span> <span class="o">!=</span> <span class="n">cave</span><span class="p">)</span> <span class="kr">else</span> <span class="n">graph</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos possíveis caminhos</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">search</span> <span class="kr">in</span> <span class="n">searches</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">get_paths</span><span class="p">(</span><span class="n">graph_</span><span class="p">,</span> <span class="n">search</span><span class="p">,</span> <span class="n">boost</span> <span class="o">=</span> <span class="n">boost</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Uma opção é não remover o nó do grafo e usar o boost</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="n">boost</span> <span class="o">&amp;&amp;</span> <span class="n">is_small</span> <span class="o">&amp;&amp;</span> <span class="n">cave</span> <span class="o">!=</span> <span class="s">&#34;start&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nf">get_paths</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">search</span><span class="p">,</span> <span class="n">boost</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Retornar lista global</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">all_paths</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler arestas do grafo e retornar conta dos caminhos distintos</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/12b_passage_pathing.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">col_names</span> <span class="o">=</span> <span class="s">&#34;path&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;orig&#34;</span><span class="p">,</span> <span class="s">&#34;dest&#34;</span><span class="p">),</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="nf">rev</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">d</span><span class="p">))))}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">dest</span> <span class="o">!=</span> <span class="s">&#34;start&#34;</span><span class="p">,</span> <span class="n">orig</span> <span class="o">!=</span> <span class="s">&#34;end&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">get_paths</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="n">str_c</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;|&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">unique</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">length</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 133360</span></span></span></code></pre></div><h2 id="origami-transparente-a">Origami Transparente (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/13">dia 13</a> foi um belo alívio comparado
com o dia anterior. Nossa missão hoje era descobrir o código de um sensor a
partir de um código escrito em papel transparente. A entrada era uma série de
coordenadas de pontos no papel e uma sequência de instruções de como dobrar o
papel para obter o código final.</p>
<p>Partindo do princípio de que a matriz começava no ponto <code>(0, 0)</code> na esqueda
superior, o primeiro item pedia para que lêssemos a nossa lista de coordenadas e
contasse o número de pontos (<code>#</code>) visíveis depois de realizar a primeira
instrução que nos era dada. Para ilustrar como as dobras ocorriam, veja os
resultados de uma dobra em <code>y = 7</code> e, depois, de uma dobra em <code>x = 5</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Papel inicial</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...#..#..#.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...#....#.#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .#....#.##.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ......#...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #.#........</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Linha em y = 7</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...#..#..#.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...#....#.#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -----------</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .#....#.##.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ......#...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #..........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #.#........</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Resultado da primeira dobra</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #.##..#..#.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ......#...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .#.#..#.###</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...........</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Linha em x = 5</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #.##.|#..#.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#|.....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....|#...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#|.....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .#.#.|#.###</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....|.....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....|.....</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Resultado final</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #####</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #...#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #####</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....</span></span></span></code></pre></div><p>O maior desafio no código em R foi arrumar todas as coordenadas e sub-matrizes
para um sistema que começa em 1 e não em 0. Eu também resolvi fazer uma aposta:
o primeiro item pedia para fazer apenas a primeira dobra, então eu imaginei que
o segundo item pediria para fazer todas. Minha decisão, portanto, foi tentar já
generalizar meu algortimo para que ele funcionasse com o mínimo de alterações
possíveis para realizar várias dobras.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler tabela de onde os pontos estão</span>
</span></span><span class="line"><span class="cl"><span class="n">dots</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/13a_transparent_origami.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_subset</span><span class="p">(</span><span class="s">&#34;^[0-9]&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;dot&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">dot</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;x&#34;</span><span class="p">,</span> <span class="s">&#34;y&#34;</span><span class="p">),</span> <span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">as.integer</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">`+`</span><span class="p">,</span> <span class="m">1L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler instruções das dobras</span>
</span></span><span class="line"><span class="cl"><span class="n">instructions</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/13a_transparent_origami.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_subset</span><span class="p">(</span><span class="s">&#34;^[^0-9]&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;fold&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">separate</span><span class="p">(</span><span class="n">fold</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;axis&#34;</span><span class="p">,</span> <span class="s">&#34;line&#34;</span><span class="p">),</span> <span class="s">&#34;=&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">axis</span> <span class="o">=</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">axis</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">line</span> <span class="o">=</span> <span class="nf">as.integer</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="o">+</span> <span class="m">1L</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Colocar os pontos no papel</span>
</span></span><span class="line"><span class="cl"><span class="n">paper</span> <span class="o">&lt;-</span> <span class="nf">matrix</span><span class="p">(</span><span class="kc">FALSE</span><span class="p">,</span> <span class="n">nrow</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">dots</span><span class="o">$</span><span class="n">y</span><span class="p">),</span> <span class="n">ncol</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">dots</span><span class="o">$</span><span class="n">x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">dots</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">paper[dots</span><span class="o">$</span><span class="n">y[i]</span><span class="p">,</span> <span class="n">dots</span><span class="o">$</span><span class="n">x[i]]</span> <span class="o">&lt;-</span> <span class="kc">TRUE</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rodar apenas a primeira instrução</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Achar o eixo e o ponto da dobra</span>
</span></span><span class="line"><span class="cl">  <span class="n">axis</span> <span class="o">&lt;-</span> <span class="n">instructions</span><span class="o">$</span><span class="n">axis[i]</span>
</span></span><span class="line"><span class="cl">  <span class="n">line</span> <span class="o">&lt;-</span> <span class="n">instructions</span><span class="o">$</span><span class="n">line[i]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Dobras de acordo com o eixo</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">axis</span> <span class="o">==</span> <span class="s">&#34;x&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Número de colunas à direita da dobra</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span> <span class="o">&lt;-</span> <span class="nf">length</span><span class="p">((</span><span class="n">line</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">paper</span><span class="p">)</span><span class="n">[2]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Pegar colunas à direita, invertê-las e fazer um OR com o lado esquerdo</span>
</span></span><span class="line"><span class="cl">    <span class="n">paper[</span><span class="p">,</span> <span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="n">size</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">      <span class="n">paper[</span><span class="p">,</span> <span class="p">(</span><span class="n">line</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">+</span> <span class="n">size</span><span class="p">)</span><span class="n">][</span><span class="p">,</span> <span class="n">size</span><span class="o">:</span><span class="m">1</span><span class="n">]</span> <span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">paper[</span><span class="p">,</span> <span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="n">size</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Descartar colunas representando o papel dobrado</span>
</span></span><span class="line"><span class="cl">    <span class="n">paper</span> <span class="o">&lt;-</span> <span class="n">paper[</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Número de linhas abaixo da dobra</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span> <span class="o">&lt;-</span> <span class="nf">length</span><span class="p">((</span><span class="n">line</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">paper</span><span class="p">)</span><span class="n">[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Pegar linhas abaixo da dobra, invertê-las e fazer um AND com as acima</span>
</span></span><span class="line"><span class="cl">    <span class="n">paper</span><span class="nf">[</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="n">size</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">),</span> <span class="n">]</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">      <span class="n">paper</span><span class="nf">[</span><span class="p">(</span><span class="n">line</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">+</span> <span class="n">size</span><span class="p">),</span> <span class="n">][size</span><span class="o">:</span><span class="m">1</span><span class="p">,</span> <span class="n">]</span> <span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">paper</span><span class="nf">[</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="n">size</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">),</span> <span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Descartar linhas representando o papel dobrado</span>
</span></span><span class="line"><span class="cl">    <span class="n">paper</span> <span class="o">&lt;-</span> <span class="n">paper[1</span><span class="o">:</span><span class="p">(</span><span class="n">line</span> <span class="o">-</span> <span class="m">1</span><span class="p">),</span> <span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contar pontos no papel</span>
</span></span><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="n">paper</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 765</span></span></span></code></pre></div><h2 id="origami-transparente-b">Origami Transparente (B)</h2>
<p>E minha aposta valeu à pena! De fato o enunciado da parte 2 pedia para que
realizássemos todas as dobras do nosso conjunto de instruções. No final, se tudo
estivesse correto, os <code>#</code> e <code>.</code> do papel deveriam formar 8 letras maiúsculas.</p>
<p>A única alteração no código foi trocar a condição do <code>for</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Iterar por todas as instruções</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">instructions</span><span class="p">)))</span></span></span></code></pre></div><p>E, no final, também foi necessário fazer um print melhor da matriz:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Imprimir os pontos de um jeito mais amigável</span>
</span></span><span class="line"><span class="cl"><span class="n">paper</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">paper</span><span class="p">,</span> <span class="s">&#34;#&#34;</span><span class="p">,</span> <span class="s">&#34;.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">paper</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cat</span><span class="p">(</span><span class="n">paper[i</span><span class="p">,</span> <span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cat</span><span class="p">(</span><span class="s">&#34;\n&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # # # . . # # # # . # . . # . # # # # . # . . . . # # # . . . # # . . # . . # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # . . # . . . . # . # . # . . . . . # . # . . . . # . . # . # . . # . # . . # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # . . # . . . # . . # # . . . . . # . . # . . . . # . . # . # . . . . # # # # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # # # . . . # . . . # . # . . . # . . . # . . . . # # # . . # . # # . # . . # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # . # . . # . . . . # . # . . # . . . . # . . . . # . . . . # . . # . # . . # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # . . # . # # # # . # . . # . # # # # . # # # # . # . . . . . # # # . # . . # .</span></span></span></code></pre></div><h2 id="polimerização-estendida-a">Polimerização Estendida (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/14">14º dia</a> do AoC foi muito demorado de
resolver para mim. Apesar de ambas as soluções abaixo serem &ldquo;simples&rdquo;, levei
horas para encontrar um jeito razoável de resolver o segundo item e,
infelizmente, só consegui depois de olhar uma dica na internet que deixou tudo
mais simples.</p>
<p>Desta vez nossa missão era estender um molde de polímero através de um conjunto
de regras de reação. A primeira linha da entrada era o molde e, a partir daí,
tínhamos as regras de inserção:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># NNCB</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># CH -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># HH -&gt; N</span>
</span></span><span class="line"><span class="cl"><span class="c1"># CB -&gt; H</span>
</span></span><span class="line"><span class="cl"><span class="c1"># NH -&gt; C</span>
</span></span><span class="line"><span class="cl"><span class="c1"># HB -&gt; C</span>
</span></span><span class="line"><span class="cl"><span class="c1"># HC -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># HN -&gt; C</span>
</span></span><span class="line"><span class="cl"><span class="c1"># NN -&gt; C</span>
</span></span><span class="line"><span class="cl"><span class="c1"># BH -&gt; H</span>
</span></span><span class="line"><span class="cl"><span class="c1"># NC -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># NB -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># BN -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># BB -&gt; N</span>
</span></span><span class="line"><span class="cl"><span class="c1"># BC -&gt; B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># CC -&gt; N</span>
</span></span><span class="line"><span class="cl"><span class="c1"># CN -&gt; C</span></span></span></code></pre></div><p>As regras eram fáceis de entender. Cada uma delas indicava que, quando os dois
elementos da esquerda se encontravam, entre eles apareceria o elemento da
direita. Uma rodada de reação envolvia estender todos os pares da cadeia
polimérica; no caso do exemplo, isso transformaria <code>NNCB</code> em <code>NCNBCHB</code>.</p>
<p>Após 10 iterações, deveríamos contar o número de ocorrências do elemento mais
comum da cadeia e subtrair dele o número de ocorrências do elemento menos comum
da cadeia. Esta seria a resposta do problema.</p>
<p>Meu código para o primeiro item acabou seguindo o que chamamos de estratégia de
<a href="https://pt.wikipedia.org/wiki/Busca_por_for%C3%A7a_bruta">força bruta</a>. A cada
iteração, eu quebrava o polímero nos seus pares de elementos e fazia um join com
a tabela de regras; depois era só colar tudo em uma string só e seguir em
frente. No final eu só precisava encontrar as letras mais e menos comuns da
string e subtraí-las.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler modelo como string</span>
</span></span><span class="line"><span class="cl"><span class="n">poly</span> <span class="o">&lt;-</span> <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="s">&#34;data-raw/14a_extended_polymerization.txt&#34;</span><span class="p">,</span> <span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler regras como tabela</span>
</span></span><span class="line"><span class="cl"><span class="n">rules</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/14a_extended_polymerization.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">skip</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;pair&#34;</span><span class="p">,</span> <span class="s">&#34;rm&#34;</span><span class="p">,</span> <span class="s">&#34;insertion&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">rm</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">insertion</span> <span class="o">=</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">pair</span><span class="p">,</span> <span class="s">&#34;(.)(.)&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;\\1&#34;</span><span class="p">,</span> <span class="n">insertion</span><span class="p">,</span> <span class="s">&#34;\\2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Executar uma rodada de inserções</span>
</span></span><span class="line"><span class="cl"><span class="n">do_insertions</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">poly</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">poly</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">accumulate</span><span class="p">(</span><span class="o">~</span><span class="nf">paste0</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="n">.y</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">utils</span><span class="o">::</span><span class="nf">tail</span><span class="p">(</span><span class="m">-1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="o">~</span><span class="n">rules[rules</span><span class="o">$</span><span class="n">pair</span> <span class="o">==</span> <span class="n">.x</span><span class="p">,</span> <span class="n">]</span><span class="o">$</span><span class="n">insertion</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="o">~</span><span class="nf">paste0</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">.y</span><span class="p">,</span> <span class="m">-2</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rodar do_insertions() 10 vezes e fazer el. mais comum - el. menos comum</span>
</span></span><span class="line"><span class="cl"><span class="m">10</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">seq_len</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="o">~</span><span class="nf">do_insertions</span><span class="p">(</span><span class="n">.x</span><span class="p">),</span> <span class="n">.init</span> <span class="o">=</span> <span class="n">poly</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">table</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> <span class="nf">list</span><span class="p">(</span><span class="n">t</span><span class="nf">[which.max</span><span class="p">(</span><span class="n">t</span><span class="p">)</span><span class="n">]</span><span class="p">,</span> <span class="n">t</span><span class="nf">[which.min</span><span class="p">(</span><span class="n">t</span><span class="p">)</span><span class="n">]</span><span class="p">)}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="n">`-`</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">abs</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">unname</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2584</span></span></span></code></pre></div><h2 id="polimerização-estendida-b">Polimerização Estendida (B)</h2>
<p>O segundo item parecia suspeitamente simples, mas eu estava redondamente
enganado. A única instrução era repetir o problema do primeiro item para 40
iterações ao invés de 10. Pode parecer que eu não precisaria nem mudar meu
código, mas note que no primeiro item a minha cadeia polimérica só chegou a ter
19457 letras. No segundo item a cadeia chegaria a&hellip; mais de 20 trilhões.</p>
<p>Seria necessário mudar de estratégia e foi aí que eu empaquei. Tentei diversas
formas de manter apenas o número de letras na cadeia, sem armazenar a cadeia em
si, mas nada funcionava. Eu até notei que a primeira e a última letras da cadeia
nunca mudavam, mas isso não me ajudou.</p>
<p>Depois de procurar por dicas no
<a href="https://www.reddit.com/r/adventofcode">subreddit do AoC</a>, finalmente achei uma
boa alma que havia feito uma observação incrível:</p>
<blockquote>
<p>Sempre podemos manter apenas a contagem de pares distintos na cadeia. Se
tivermos, por exemplo, um par AC aparecendo n = 10 vezes na cadeia e uma regra
AC -&gt; B, então na próxima iteração podemos adicionar à nossa contagem AB e BC,
cada uma aparecendo n = 10 vezes.</p>
</blockquote>
<p>Até aí eu já sabia, era essencialmente o que eu fazia manualmente no item 1. O
problema é que, mantendo apenas as contagens dos pares, isso repetiria a letra B
duas vezes, totalizando A 10 vezes, C 10 vezes e B <em>20</em> vezes. A ideia que veio
a seguir, entretanto, foi o que realmente resolveu o problema:</p>
<blockquote>
<p>Se pensarmos na cadeia como um todo, todos as letras serão contadas 2 vezes,
exceto pela primeira e pela última, pois elas nunca ficam no meio de uma
reação. O número de ocorrências de cada letra é, portanto, n / 2, exceto pelas
letras que aparecem no início e no fim, paras quais a fórmula é (n + 1) / 2.</p>
</blockquote>
<p>Depois disso o item 2 podia ser solucionado facilmente.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Registrar a primeira e a última letras da cadeia original</span>
</span></span><span class="line"><span class="cl"><span class="n">orig</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/14b_extended_polymerization.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="s">&#34;^(.).*?(.)$&#34;</span><span class="p">,</span> <span class="s">&#34;\\1\\2&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler modelo já no formato de contagem de pares</span>
</span></span><span class="line"><span class="cl"><span class="n">poly</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/14b_extended_polymerization.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">accumulate</span><span class="p">(</span><span class="o">~</span><span class="nf">paste0</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="n">.y</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">utils</span><span class="o">::</span><span class="nf">tail</span><span class="p">(</span><span class="m">-1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;pair&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">count</span><span class="p">(</span><span class="n">pair</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler regras como tabela</span>
</span></span><span class="line"><span class="cl"><span class="n">rules</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/14b_extended_polymerization.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_table</span><span class="p">(</span><span class="n">skip</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">col_names</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;pair&#34;</span><span class="p">,</span> <span class="s">&#34;rm&#34;</span><span class="p">,</span> <span class="s">&#34;insertion&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">rm</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">insertion</span> <span class="o">=</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">pair</span><span class="p">,</span> <span class="s">&#34;(.)(.)&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;\\1&#34;</span><span class="p">,</span> <span class="n">insertion</span><span class="p">,</span> <span class="s">&#34;\\2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Executar uma rodada de inserções</span>
</span></span><span class="line"><span class="cl"><span class="n">do_insertions</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">poly</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">poly</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">left_join</span><span class="p">(</span><span class="n">rules</span><span class="p">,</span> <span class="s">&#34;pair&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">insertion</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">insertion</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="n">str_extract</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;^..&#34;</span><span class="p">,</span> <span class="s">&#34;..$&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">insertion</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">pair</span> <span class="o">=</span> <span class="n">insertion</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rodar do_insertions() 40 vezes e fazer el. mais comum - el. menos comum</span>
</span></span><span class="line"><span class="cl"><span class="m">40</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">seq_len</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="o">~</span><span class="nf">do_insertions</span><span class="p">(</span><span class="n">.x</span><span class="p">),</span> <span class="n">.init</span> <span class="o">=</span> <span class="n">poly</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">elem</span> <span class="o">=</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">pair</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">elem</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">elem</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">elem</span> <span class="o">%in%</span> <span class="n">orig</span><span class="p">,</span> <span class="n">n</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="n">n</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">/</span> <span class="m">2</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="nf">max</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">|</span> <span class="n">n</span> <span class="o">==</span> <span class="nf">min</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="n">`-`</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">abs</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">format</span><span class="p">(</span><span class="n">scientific</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 3816397135460</span></span></span></code></pre></div><h2 id="quítons-a">Quítons (A)</h2>
<p>No <a href="https://adventofcode.com/2021/day/15">15º dia</a> do AoC eu demorei muito mais
do que deveria. Apesar de ter entendido bem o enunciado e ter identificado
rapidamente o caminho para a solução, eu empaquei na <em>implementação</em> do
algoritmo. No final achei melhor pegar uma versão pronta do algoritmo para não
perder mais horas com isso.</p>
<p>Novamente o enunciado envolvia um submarino, uma caverna, etc. Passar por cada
ponto da caverna vinha com um certo risco que variava entre 1 e 9 e nosso
objetivo era levar o submarino do ponto esquerdo superior até o ponto esquerdo
inferior passando pelo caminho com menor risco total. A saída do programa
deveria ser a soma do risco de todos os pontos do caminho (sem incluir o ponto
de entrada, pois já começávamos nele).</p>
<p>A esse ponto, qualquer um que tenha aprendido sobre grafos já deve estar com o
sentido aranha ativado. Esse é um problema clássico da Computação que pode ser
facilmente solucionado pelo <a href="https://pt.wikipedia.org/wiki/Algoritmo_de_Dijkstra">algoritmo de
Dijkstra</a>. Algumas
alterações são necessárias, mas todas podem ser feitas antes de executar o
algoritmo.</p>
<p>O passo-a-passo do código é mais ou menos o seguinte:</p>
<ol>
<li>
<p>Marcar todos os pontos como não visitados. Criar um conjunto com todos os
pontos não visitador chamado <em>conjunto não visitado</em>.</p>
</li>
<li>
<p>Atribuir a todos os pontos um risco temporário: ele deve ser 0 para o nó
inicial e infinito para o resto. O risco temporário de um ponto <code>v</code> é o risco
total do caminho de menor risco já descoberto entre <code>v</code> e o ponto inicial. Como
no começo não conhecemos nenhum outro ponto além do inicial, todos os riscos
temporários começam como infinito. Fixar o ponto inicial como o atual.</p>
</li>
<li>
<p>Para o ponto atual, considerar todos os seus vizinhos não vizitados e
calcular os seus riscos temporários através do ponto atual. Comparar o novo
risco temporário ao risco atual e atribuir o menor dos dois. Por exemplo, se o
risco do ponto atual <code>A</code> é 6 e o seu vizinho <code>B</code> tem risco 2, então o risco de
chegar em <code>B</code> por <code>A</code> é 6 + 2 = 8. Se o risco temporário de <code>B</code> até agora era
maior que 8, então ele deve virar 8. Caso contrário, nada muda.</p>
</li>
<li>
<p>Quando já tivermos considerado todos os vizinhos não visitados do ponto
atual, marcar o ponto atual como visitado e removê-lo do conjunto não visitado.
Um ponto visitado nunca será checado de novo.</p>
</li>
<li>
<p>Se o ponto final houver sido marcado como visitado, então parar. O algoritmo
terminou e o risco total do melhor caminho até o distino é igual ao risco
temporário que foi atribuido ao destino.</p>
</li>
<li>
<p>Caso contrário, selecionar o ponto não visitado que tem o menor risco
temporário e torná-lo o ponto atual. Voltar ao passo 3.</p>
</li>
</ol>
<p>Normalmente o algoritmo de Dijkstra é aplicado em grafos nos quais os custos de
cada passo do caminho são atribuídos à <em>arestas</em> do grafo e não aos nós, como é
o nosso caso. Para resolver esse problema, temos que fazer uma certa ginástica
para que os custos sejam transferidos para as arestas. Cada par de nós vizinhos
ganham duas arestas direcionadas, cada uma com o risco do nó para o qual ela
aponta:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ponto atual com seus 4 vizinhos</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   7</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 9 3 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Arestas indo para o ponto atual (todas têm risco 3)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       o</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       ↓</span>
</span></span><span class="line"><span class="cl"><span class="c1"># o 3 → x ← 3 o</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       ↑</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       o</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Arestas saindo do ponto atual (todas têm o risco do vizinho)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       o</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       ↑</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       7</span>
</span></span><span class="line"><span class="cl"><span class="c1"># o ← 9 x 1 → o</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       ↓</span>
</span></span><span class="line"><span class="cl"><span class="c1">#       o</span></span></span></code></pre></div><p>Eu queria ter de fato implementado o algoritmo de Dijkstra no R por conta
própria, mas eu cometi vários erros pelo caminho (eram 7:30, não me julgue) e,
para não passar a manhã toda nisso, resolvi usar o pacote <code>cppRouting</code> para
aplicar o algoritmo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler os riscos da caverna como uma matriz</span>
</span></span><span class="line"><span class="cl"><span class="n">cave</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/15a_chiton.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">matrix</span><span class="p">(</span><span class="m">100</span><span class="p">,</span> <span class="m">100</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Criar uma tabela com os custos entre vizinhos</span>
</span></span><span class="line"><span class="cl"><span class="n">graph</span> <span class="o">&lt;-</span> <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="nf">prod</span><span class="p">(</span><span class="nf">dim</span><span class="p">(</span><span class="n">cave</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">vals</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">%%</span> <span class="m">100</span> <span class="o">!=</span> <span class="m">0</span><span class="p">)</span>  <span class="n">vals</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">%%</span> <span class="m">100</span> <span class="o">!=</span> <span class="m">1</span><span class="p">)</span>  <span class="n">vals</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="m">1L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&gt;</span> <span class="m">100</span><span class="p">)</span>        <span class="n">vals</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="m">100L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="m">9901</span><span class="p">)</span>       <span class="n">vals</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="m">100L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">node</span> <span class="o">&lt;-</span> <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">(</span><span class="n">from_vertex</span> <span class="o">=</span> <span class="n">i</span><span class="p">,</span> <span class="n">to_vertex</span> <span class="o">=</span> <span class="n">vals</span><span class="p">,</span> <span class="n">cost</span> <span class="o">=</span> <span class="n">cave[vals]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">graph</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">node</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Criar grafo e executar o algoritmo de Dijkstra</span>
</span></span><span class="line"><span class="cl"><span class="n">path</span> <span class="o">&lt;-</span> <span class="n">graph</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cppRouting</span><span class="o">::</span><span class="nf">makegraph</span><span class="p">(</span><span class="n">directed</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">cppRouting</span><span class="o">::</span><span class="nf">get_path_pair</span><span class="p">(</span><span class="n">from</span> <span class="o">=</span> <span class="m">1L</span><span class="p">,</span> <span class="n">to</span> <span class="o">=</span> <span class="m">10000L</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Calcular o risco total do caminho (subtraíndo o custo da entrada)</span>
</span></span><span class="line"><span class="cl"><span class="n">graph</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">to_vertex</span> <span class="o">%in%</span> <span class="n">path</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">to_vertex</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">cost</span> <span class="o">=</span> <span class="n">cost[1]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">risk</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">cost</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">risk</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">magrittr</span><span class="o">::</span><span class="nf">subtract</span><span class="p">(</span><span class="n">cave[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 811</span></span></span></code></pre></div><h2 id="quítons-b">Quítons (B)</h2>
<p>O segundo item seguia a mesma lógica de outros problemas desse ano: igual ao
primeiro item, mas maior. Como eu estava usando um algoritmo bastante eficiente,
não tive problema nenhum nessa parte.</p>
<p>Aqui descobríamos que, na verdade, a caverna era 5 vezes maior em cada dimensão
(ou seja, 25 vezes mais pontos). A caverna completa era, entretanto, composta
por cópias da sessão original com riscos mais elevados; para obter a versão
final da caverna era necessário juntar 25 cópias da original somando um certo
fator a cada cópia.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># +0 +1 +2 +3 +4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># +1 +2 +3 +4 +5</span>
</span></span><span class="line"><span class="cl"><span class="c1"># +2 +3 +4 +5 +6</span>
</span></span><span class="line"><span class="cl"><span class="c1"># +3 +4 +5 +6 +7</span>
</span></span><span class="line"><span class="cl"><span class="c1"># +4 +5 +6 +7 +8</span></span></span></code></pre></div><p>Seguindo o guia acima, vemos que o canto superior esquerdo da caverna maior era
igual à sessão original e, sucessivamente, chegávamos ao canto direito inferior,
que era igual à sessão original, mas o risco de cada ponto era acrescido de 8.
O único detalhe é que, quando o risco de um ponto passava de 9, ele voltava para
1 (igual aos polvos-dumbo que vimos anteriormente). O resto da solução era
igual.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar clones da caverna, somar fator de risco e juntar</span>
</span></span><span class="line"><span class="cl"><span class="n">cave</span> <span class="o">&lt;-</span> <span class="nf">cbind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="n">cave</span> <span class="o">+</span> <span class="m">0L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">1L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">2L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">3L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">4L</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="n">cave</span> <span class="o">+</span> <span class="m">1L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">2L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">3L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">4L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">5L</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="n">cave</span> <span class="o">+</span> <span class="m">2L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">3L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">4L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">5L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">6L</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="n">cave</span> <span class="o">+</span> <span class="m">3L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">4L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">5L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">6L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">7L</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="n">cave</span> <span class="o">+</span> <span class="m">4L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">5L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">6L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">7L</span><span class="p">,</span> <span class="n">cave</span> <span class="o">+</span> <span class="m">8L</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Reduzir pontos que passaram de 9</span>
</span></span><span class="line"><span class="cl"><span class="n">cave[cave</span> <span class="o">&gt;</span> <span class="m">9</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="n">cave[cave</span> <span class="o">&gt;</span> <span class="m">9</span><span class="n">]</span> <span class="o">-</span> <span class="m">9</span></span></span></code></pre></div><h2 id="decodificador-de-pacotes-a">Decodificador de Pacotes (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/16">16º problema</a> do AoC foi bastante
diverido. O enunciado era extremamente longo e cheio de detalhes, mas consegui
fazer uma implementação direta e eficiente que só não funcionou de primeira por
causa de um detalhe obscuro da função <code>strtoi()</code>.</p>
<p>Hoje nosso objetivos era decodificar pacotes binários. Eles chegavam ao nosso
submarino em hexadecimal e, depois de convertidos para binário eles tinham as
seguintes características:</p>
<ul>
<li>
<p>Os 3 primeiros bits representavam a versão do pacote;</p>
</li>
<li>
<p>Os 3 bits seguintes representavam o tipo do pacote, que podia cair em dois
casos:</p>
<ul>
<li>
<p>Se o tipo (na forma decimal) fosse igual a 4, então o pacote representaria
um valor. Isso queria dizer que o resto do pacote poderia ser quebrado em
pedaços de 5 bits com a seguinte configuração:</p>
<ul>
<li>
<p>Se o pedaço começasse com 1, então os 4 bits a seguir eram parte do valor
e deveríamos continuar lendo o pacote;</p>
</li>
<li>
<p>Se o pedaço começassem em 0, então os 4 bits a seguir eram o final do
valor e poderíamos parar de ler o pacote.</p>
</li>
</ul>
</li>
<li>
<p>Se o tipo do pacote fosse diferente de 4, então o pacote representaria um
operador. Isso queria dizer que o bit de número 7 indicava o modo do pacote:</p>
<ul>
<li>
<p>Se o indicador fosse 1, então os próximos 15 bits seriam iguais à soma dos
comprimentos de todos os sub-pacotes contidos naquele pacote operador;</p>
</li>
<li>
<p>Se o indicador fosse 0, então os próximos 11 bits seriam iguais ao número
de sub-pacotes contidos naquele pacote operador.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Simples? Longe disso. Vejamos alguns exemplos:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pacote literal (valor)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># D2FE28</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 110100101111111000101000</span>
</span></span><span class="line"><span class="cl"><span class="c1"># VVVTTTAaaaaBbbbbCcccc</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - VVV são a versão do pacote, 6.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - TTT são o tipo, 4. Então este pacote carrega um valor.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - A é 1 (continuar lendo), então aaaa são o primeiro pedaço do valor.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - B é 1 (continuar lendo), então bbbb são o segundo pedaço do valor.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - C é 0 (parar de ler), então cccc são o último pedaço do valor.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - O resto são bits extras.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - Portanto, o valor carregado por este pacote é 011111100101 = 2021.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Pacote operador com indicador 0</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 38006F45291200</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 00111000000000000110111101000101001010010001001000000000</span>
</span></span><span class="line"><span class="cl"><span class="c1"># VVVTTTILLLLLLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBBBBBB</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - VVV são a versão do pacote, 1.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - TTT são o tipo, 6. Então este pacote carrega um operador.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - I é o indicador, 0. Então este pacote tem 15 bits com os comprimentos</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   dos sub-pacotes.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - LLLLLLLLLLLLLLL contêm a soma dos comprimentos dos sub-pacotes, 27.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - AAAAAAAAAAA são um sub-pacote carregando um valor, 10.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - BBBBBBBBBBBBBBBB são um sub-pacote carregando um valor, 20.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Pacote operador com indicador 1</span>
</span></span><span class="line"><span class="cl"><span class="c1"># EE00D40C823060</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 11101110000000001101010000001100100000100011000001100000</span>
</span></span><span class="line"><span class="cl"><span class="c1"># VVVTTTILLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBCCCCCCCCCCC</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - VVV são a versão do pacote, 7.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - TTT são o tipo, 3. Então este pacote carrega um operador.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - I é o indicador, 1. Então este pacote tem 11 bits com os número de</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   sub-pacotes.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - LLLLLLLLLLL contêm o número de sub-pacotes, 3.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - AAAAAAAAAAA são um sub-pacote carregando um valor, 1.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - BBBBBBBBBBB são um sub-pacote carregando um valor, 2.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - CCCCCCCCCCC são um sub-pacote carregando um valor, 3.</span></span></span></code></pre></div><p>O ponto positivo desse enunciado enorme é que conseguimos implementar os
recursos necessários quase em sequência.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Converter string hexadecimal para string binária</span>
</span></span><span class="line"><span class="cl"><span class="n">hex_to_bits</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">hex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">hex</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">paste</span><span class="p">(</span><span class="nf">rev</span><span class="p">(</span><span class="nf">as.integer</span><span class="p">(</span><span class="nf">intToBits</span><span class="p">(</span><span class="nf">strtoi</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="m">16</span><span class="p">))))))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">magrittr</span><span class="o">::</span><span class="n">extract</span><span class="p">,</span> <span class="m">29</span><span class="o">:</span><span class="m">32</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar a versão de um pacote</span>
</span></span><span class="line"><span class="cl"><span class="n">get_version</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">strtoi</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar o tipo de um pacote</span>
</span></span><span class="line"><span class="cl"><span class="n">get_type</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">strtoi</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">6</span><span class="p">),</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>O objetivo final deste item era parsear a hierarquia de pacotes da nossa entrada
e somar as versões de todos. Minha solução envolveu, desta forma, cirar uma
&ldquo;classe&rdquo; que podia conter a versão e o comprimento de um pacote. O comprimento
era importante para descartar o número certo de bits do pacote quando tivéssemos
terminado de processar um sub-pacote.</p>
<p>Se um pacote fosse do tipo operador, então sua &ldquo;classe&rdquo; também conteria todos
os seus sub-pacotes como elementos sem nome. O código abaixo implementa o
processamento dos dois tipos de pacotes; note como foram implementadas as
&ldquo;classes&rdquo;:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar o valor de um pacote literal</span>
</span></span><span class="line"><span class="cl"><span class="n">get_literal</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">interval</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="m">7</span><span class="p">,</span> <span class="m">11</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar até o último pedaço ser encontrado</span>
</span></span><span class="line"><span class="cl">  <span class="n">literal</span> <span class="o">&lt;-</span> <span class="s">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">FALSE</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="o">!</span><span class="n">flag</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Pegar o grupo especificado pelo intervalo</span>
</span></span><span class="line"><span class="cl">    <span class="n">group</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="n">interval[1]</span><span class="p">,</span> <span class="n">interval[2]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">literal</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="n">literal</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">group</span><span class="p">,</span> <span class="m">2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Parar se este é o último pedaço, caso contrário somar 5 ao intervalo</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">as.integer</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">group</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">flag</span> <span class="o">&lt;-</span> <span class="kc">TRUE</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">interval</span> <span class="o">&lt;-</span> <span class="n">interval</span> <span class="o">+</span> <span class="m">5</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Retornar a &#34;classe&#34; que descreve o pacote</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span> <span class="o">=</span> <span class="nf">get_version</span><span class="p">(</span><span class="n">pkt</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">len</span> <span class="o">=</span> <span class="n">interval[2]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">value</span> <span class="o">=</span> <span class="nf">strtoi</span><span class="p">(</span><span class="n">literal</span><span class="p">,</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Processar um pacote operador</span>
</span></span><span class="line"><span class="cl"><span class="n">get_operator</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">indicator</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">7</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Inicializar &#34;classe&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span> <span class="o">=</span> <span class="nf">get_version</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Lidar com os 2 indicadores</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">as.integer</span><span class="p">(</span><span class="n">indicator</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Pegar o número de sub-pacotes e separar a cauda do pacote</span>
</span></span><span class="line"><span class="cl">    <span class="n">num</span> <span class="o">&lt;-</span> <span class="nf">strtoi</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">18</span><span class="p">),</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rest</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">19</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">&lt;-</span> <span class="m">18</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Iterar no número de pacotes</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">num</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Processar sub-pacote</span>
</span></span><span class="line"><span class="cl">      <span class="n">sub</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="nf">get_type</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span> <span class="o">==</span> <span class="m">4</span><span class="p">)</span> <span class="nf">get_literal</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span> <span class="kr">else</span> <span class="nf">get_operator</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">&lt;-</span> <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">+</span> <span class="n">sub</span><span class="o">$</span><span class="n">len</span>
</span></span><span class="line"><span class="cl">      <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="n">sub</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Atualizar a cauda dado o compimento do último sub-pacote</span>
</span></span><span class="line"><span class="cl">      <span class="n">rest</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">sub</span><span class="o">$</span><span class="n">len</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Pegar o limite de comprimento dos sub-pacotes e separar a cauda</span>
</span></span><span class="line"><span class="cl">    <span class="n">lim</span> <span class="o">&lt;-</span> <span class="nf">strtoi</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">22</span><span class="p">),</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rest</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span> <span class="m">23</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">&lt;-</span> <span class="m">22</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Iterar enquanto os sub-pacotes não tiverem passado do limite</span>
</span></span><span class="line"><span class="cl">    <span class="kr">while</span> <span class="p">(</span><span class="n">lim</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Processar sub-pacote</span>
</span></span><span class="line"><span class="cl">      <span class="n">sub</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="nf">get_type</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span> <span class="o">==</span> <span class="m">4</span><span class="p">)</span> <span class="nf">get_literal</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span> <span class="kr">else</span> <span class="nf">get_operator</span><span class="p">(</span><span class="n">rest</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">&lt;-</span> <span class="n">out</span><span class="o">$</span><span class="n">len</span> <span class="o">+</span> <span class="n">sub</span><span class="o">$</span><span class="n">len</span>
</span></span><span class="line"><span class="cl">      <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="n">sub</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Atualizar a cauda dado o compimento do último sub-pacote</span>
</span></span><span class="line"><span class="cl">      <span class="n">rest</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">sub</span><span class="o">$</span><span class="n">len</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">lim</span> <span class="o">&lt;-</span> <span class="n">lim</span> <span class="o">-</span> <span class="n">sub</span><span class="o">$</span><span class="n">len</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>O último passo do meu código era achatar toda a estrutura de árvore que seria
devolvida pelas funções acima e somar todos os comprimentos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Somar todas as versões do pacote representado por um hex</span>
</span></span><span class="line"><span class="cl"><span class="n">sum_versions</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">hex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar a árvore de pacotes representada pelo hex</span>
</span></span><span class="line"><span class="cl">  <span class="n">pkt</span> <span class="o">&lt;-</span> <span class="nf">hex_to_bits</span><span class="p">(</span><span class="n">hex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">pkts</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="nf">get_type</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="o">==</span> <span class="m">4</span><span class="p">)</span> <span class="nf">get_literal</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="kr">else</span> <span class="nf">get_operator</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Achatar árvore</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="nf">vec_depth</span><span class="p">(</span><span class="n">pkts</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">pkts</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten</span><span class="p">(</span><span class="n">pkts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Somar versões</span>
</span></span><span class="line"><span class="cl">  <span class="n">pkts</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">magrittr</span><span class="o">::</span><span class="nf">extract</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">pkts</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;version&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler pacotes de um hex e somar versões</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/16a_packet_decoder.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum_versions</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 991</span></span></span></code></pre></div><h2 id="decodificador-de-pacotes-b">Decodificador de Pacotes (B)</h2>
<p>O segundo item era mais ou menos o que eu já esperava. Os tipos dos pacotes
tinham um significado maior, ou seja, cada sub-tipo de pacote operador indicava
uma operação matemática que deveria ser aplicada no valor dos seus sub-pacotes.</p>
<ul>
<li>
<p>A operação 0 é soma (<code>sum()</code>).</p>
</li>
<li>
<p>A operação 1 é produto (<code>prod()</code>).</p>
</li>
<li>
<p>A operação 2 é mínimo (<code>min()</code>).</p>
</li>
<li>
<p>A operação 3 é máximo (<code>max()</code>).</p>
</li>
<li>
<p>A operação 5 é maior que (<code>&gt;</code>).</p>
</li>
<li>
<p>A operação 6 é menor que (<code>&lt;</code>).</p>
</li>
<li>
<p>A operação 7 é igual (<code>==</code>).</p>
</li>
</ul>
<p>Ou seja, se um pacote tiver a estrutura
<code>(operador + (operador * (valor 1) (valor 2)) (valor 3))</code>, então a expressão
aritmética resultante seria <code>(1 * 2) + 3)</code>. Nosso objetivo final era calcular o
valor da expressão que o nosso pacote representava. Felizmente, o meu script
anterior funcionava muito bem com essa alteração!</p>
<p>Eu troquei o elemento <code>version</code> da &ldquo;classe&rdquo; por <code>type</code> (o tipo do operador) e
adicionei o seguinte no final do código:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Avaliar a árvore de pacotes</span>
</span></span><span class="line"><span class="cl"><span class="n">get_value</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Funções correspondentes aos tipos</span>
</span></span><span class="line"><span class="cl">  <span class="n">fun</span> <span class="o">&lt;-</span> <span class="kr">switch</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">tree</span><span class="o">$</span><span class="n">type</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;0&#34;</span> <span class="o">=</span> <span class="n">sum</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;1&#34;</span> <span class="o">=</span> <span class="n">prod</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;2&#34;</span> <span class="o">=</span> <span class="n">min</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;3&#34;</span> <span class="o">=</span> <span class="n">max</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;5&#34;</span> <span class="o">=</span> <span class="n">`&gt;`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;6&#34;</span> <span class="o">=</span> <span class="n">`&lt;`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;7&#34;</span> <span class="o">=</span> <span class="n">`==`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aplicar função aos sub-pacotes</span>
</span></span><span class="line"><span class="cl">  <span class="n">apply_fun</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">tree</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">keep</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">get_value</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="n">fun</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aplicar recursivamente</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">tree</span><span class="o">$</span><span class="n">type</span> <span class="o">==</span> <span class="m">4</span><span class="p">)</span> <span class="n">tree</span><span class="o">$</span><span class="n">value</span> <span class="kr">else</span> <span class="nf">as.numeric</span><span class="p">(</span><span class="nf">apply_fun</span><span class="p">(</span><span class="n">tree</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Decodificar a expressão de um pacote hex</span>
</span></span><span class="line"><span class="cl"><span class="n">decode</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">hex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">pkt</span> <span class="o">&lt;-</span> <span class="nf">hex_to_bits</span><span class="p">(</span><span class="n">hex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">tree</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="nf">get_type</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="o">==</span> <span class="m">4</span><span class="p">)</span> <span class="nf">get_literal</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span> <span class="kr">else</span> <span class="nf">get_operator</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nf">get_value</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler pacotes de um hex e calcular o valor da expressão</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/16b_packet_decoder.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">decode</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">format</span><span class="p">(</span><span class="n">scientific</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1264485568252</span></span></span></code></pre></div><p>P.S.: Mas isso não funcionou de primeira! Eu recebi um belo <code>NA</code> ao final da
execução e demorei para entender a causa&hellip; No final eu descobri que a função
<code>strtoi()</code> retorna <code>NA</code> quando o resultado é grande demais. A solução foi
trocá-la por uma função própria:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">strton</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">y</span> <span class="o">&lt;-</span> <span class="nf">as.numeric</span><span class="p">(</span><span class="nf">strsplit</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span><span class="n">[[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">(</span><span class="n">y</span> <span class="o">*</span> <span class="m">2</span><span class="nf">^rev</span><span class="p">((</span><span class="nf">seq_along</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="cesta-de-três-a">Cesta de Três (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/17">17º dia</a> do AoC foi uma ótima quebra em
relação aos últimos. O enunciado era simples de entender e a solução foi fácil
de criar, tudo que eu precisava depois de uma semana cansativa.</p>
<p>Hoje precisávamos tentar encontrar a chave do nosso submarino em uma fossa
marinha. A sonda que tínhamos a bordo podia ser arremessada a partir do ponto
(0, 0) com qualquer velocidade inteira tanto no eixo x quanto no y. A entrada
do problema era a posição do alvo e a saída do primeiro item deveria ser a
altura máxima que podíamos arremessar a sonda de modo que ela ainda atingisse
o alvo.</p>
<p>As regras para a aceleração da sonda a cada passo eram as seguintes:</p>
<ul>
<li>
<p>A posição x da sonda aumenta um valor igual à sua velocidade x.</p>
</li>
<li>
<p>A posição y da sonda aumenta um valor igual à sua velocidade y.</p>
</li>
<li>
<p>Por causa do atrito, a velocidade x da sonda muda em 1 um direção a 0 (ou
seja, ela diminui em 1 se a velocidade for maior que 0 e aumenta em 1 caso
contrário).</p>
</li>
<li>
<p>Por causa da gravidade, a velocidade y da sonda diminui em 1.</p>
</li>
</ul>
<p>O grande truque do exercício era identificar todas as velocidades possíveis da
sonda e depois verificar qual o levava à maior altura. Como o alvo estava sempre
abaixo e à direita do (0, 0), podíamos estabelecer os limites inferiores e
superiores para as velocidades x e y:</p>
<ul>
<li>
<p>A velocidade x necessariamente tem que ser maior que 0, já que precisamos que
a sonda se mova para frente. Adicionalmente, velocidade x máxima não pode ser
maior que a fronteira direita do alvo; se o alvo terminar, por exemplo, em
x = 10, nunca vamos acertá-lo jogando o módulo para frente com velocidade maior
que 10.</p>
</li>
<li>
<p>Os limites da velocidade y são mais difícil de entender. Em primeiro lugar,
ela nunca pode ser menor do que a fronteira inferior do alvo (pensando na mesma
lógica que usamos antes, se o alvo terminar, por exemplo, em y = -10, nunca
vamos acertá-lo jogando a sonda para baixo com velocidade menor que -10). O
limite superior vem do fato de que se jogarmos a sonda para cima, não importando
a velocidade, ela eventualmente vai voltar a y = 0 com velocidade igual à
velocidade inicial menos 1, mas com sinal negativo; sendo assim, a velocidade y
máxima é igual ao valor absoluto do limite inferior do alvo.</p>
</li>
</ul>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Velocidade inicial: (6,3)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .........(3,0).#..#.(2,-1)........</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....(4,1).#........#.(1,-2)......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># (5,2).#..............#.(0,-3).....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># S.(6,3)..............#.(0,-4).....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .....................#.(0,-5).....</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....................TTTTTTTTTTT...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....................TTTTTTTTTTT...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....................TTTTTTTTTTT...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....................TTTTTTTTTTT...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....................T#T(0,-6)TT...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..................................</span></span></span></code></pre></div><p>Note no diagrama acima a simetria da trajetória no eixo y. Assim fica mais fácil
entender porque, por exemplo, se o limite inferior do alvo for y = -10, então
nunca podemos jogar a sonda para cima com velocidade maior que 9; ela voltará
para y = 0 com velocidade -10 e acertará exatamente a fronteira de baixo do
alvo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler alvo como uma tabela de coordenadas</span>
</span></span><span class="line"><span class="cl"><span class="n">target</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/17a_trick_shot.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;[=,]&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_subset</span><span class="p">(</span><span class="s">&#34;^[0-9-]&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="s">&#34;\\.\\.&#34;</span><span class="p">,</span> <span class="s">&#34;:&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">eval</span><span class="p">(</span><span class="nf">parse</span><span class="p">(</span><span class="n">text</span> <span class="o">=</span> <span class="n">.x</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">cross</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">transpose</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;x&#34;</span><span class="p">,</span> <span class="s">&#34;y&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Todas as possíveis combinações de velocidades x e y válidas</span>
</span></span><span class="line"><span class="cl"><span class="n">vels</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">cross</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="m">1</span><span class="o">:</span><span class="nf">max</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">x</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">min</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">)</span><span class="o">:</span><span class="nf">abs</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">))</span></span></span></code></pre></div><p>Para calcular a altura máxima que poderíamos arremessar a sonda, eu simulei a
trajetória a partir de cada um dos pares de velocidades válidas e guardei a
altura máxima à qual a sonda chegava. No final da iteração, se a sonda de fato
atingisse o alvo, então eu comparava a altura máxima dessa combinação com a
altura máxima global e mantinha a maior.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Verificar quais pares de velocidades funcionam e pegar a altura máxima</span>
</span></span><span class="line"><span class="cl"><span class="n">max_height</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">vel</span> <span class="kr">in</span> <span class="n">vels</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Posição inicial</span>
</span></span><span class="line"><span class="cl">  <span class="n">x_pos</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="n">y_pos</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Velocidades iniciais</span>
</span></span><span class="line"><span class="cl">  <span class="n">x_vel</span> <span class="o">&lt;-</span> <span class="n">vel[[1]]</span>
</span></span><span class="line"><span class="cl">  <span class="n">y_vel</span> <span class="o">&lt;-</span> <span class="n">vel[[2]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar a altura máxima deste par de velocidades</span>
</span></span><span class="line"><span class="cl">  <span class="n">max_height_</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">y_pos</span> <span class="o">&gt;=</span> <span class="nf">min</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">x_pos</span> <span class="o">&lt;=</span> <span class="nf">max</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">x</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Atualizar posições</span>
</span></span><span class="line"><span class="cl">    <span class="n">x_pos</span> <span class="o">&lt;-</span> <span class="n">x_pos</span> <span class="o">+</span> <span class="n">x_vel</span>
</span></span><span class="line"><span class="cl">    <span class="n">y_pos</span> <span class="o">&lt;-</span> <span class="n">y_pos</span> <span class="o">+</span> <span class="n">y_vel</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Atualizar altura máxima local</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">y_pos</span> <span class="o">&gt;</span> <span class="n">max_height_</span><span class="p">)</span> <span class="n">max_height_</span> <span class="o">&lt;-</span> <span class="n">y_pos</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Se o par de fato leva ao alvo, atualizar altura máxima global</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">x_pos</span> <span class="o">%in%</span> <span class="n">target</span><span class="o">$</span><span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y_pos</span> <span class="o">%in%</span> <span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">if</span> <span class="p">(</span><span class="n">max_height_</span> <span class="o">&gt;</span> <span class="n">max_height</span><span class="p">)</span> <span class="n">max_height</span> <span class="o">&lt;-</span> <span class="n">max_height_</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Atualizar velocidades</span>
</span></span><span class="line"><span class="cl">    <span class="n">x_vel</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="n">x_vel</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="n">x_vel</span> <span class="o">-</span> <span class="m">1</span> <span class="kr">else</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="n">y_vel</span> <span class="o">&lt;-</span> <span class="n">y_vel</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Retornar a altura máxima global</span>
</span></span><span class="line"><span class="cl"><span class="n">max_height</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 4753</span></span></span></code></pre></div><h2 id="cesta-de-três-b">Cesta de Três (B)</h2>
<p>Chegando no item 2, eu percebi que tinha dado muita sorte. O enunciado aqui
pedia para encontrarmos o número de velocidades iniciais da sonda que a faziam
chegar ao alvo. Meu código anterior já encontrava todos os pares válidos, mas
utilizava isso para atualizar a altura máxima; só era necessário trocar a
variável sendo atualizada dentro do <code>while</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Verificar pares de velocidades que funcionam e contá-los</span>
</span></span><span class="line"><span class="cl"><span class="n">n_works</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">vel</span> <span class="kr">in</span> <span class="n">vels</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Posição inicial</span>
</span></span><span class="line"><span class="cl">  <span class="n">x_pos</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="n">y_pos</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Velocidades iniciais</span>
</span></span><span class="line"><span class="cl">  <span class="n">x_vel</span> <span class="o">&lt;-</span> <span class="n">vel[[1]]</span>
</span></span><span class="line"><span class="cl">  <span class="n">y_vel</span> <span class="o">&lt;-</span> <span class="n">vel[[2]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar a altura máxima deste par de velocidades</span>
</span></span><span class="line"><span class="cl">  <span class="n">max_height_</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">y_pos</span> <span class="o">&gt;=</span> <span class="nf">min</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">x_pos</span> <span class="o">&lt;=</span> <span class="nf">max</span><span class="p">(</span><span class="n">target</span><span class="o">$</span><span class="n">x</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Atualizar posições</span>
</span></span><span class="line"><span class="cl">    <span class="n">x_pos</span> <span class="o">&lt;-</span> <span class="n">x_pos</span> <span class="o">+</span> <span class="n">x_vel</span>
</span></span><span class="line"><span class="cl">    <span class="n">y_pos</span> <span class="o">&lt;-</span> <span class="n">y_pos</span> <span class="o">+</span> <span class="n">y_vel</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Se o par de fato leva ao alvo, atualizar contador</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">x_pos</span> <span class="o">%in%</span> <span class="n">target</span><span class="o">$</span><span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y_pos</span> <span class="o">%in%</span> <span class="n">target</span><span class="o">$</span><span class="n">y</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">n_works</span> <span class="o">&lt;-</span> <span class="n">n_works</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">      <span class="kr">break</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Atualizar velocidades</span>
</span></span><span class="line"><span class="cl">    <span class="n">x_vel</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="n">x_vel</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="n">x_vel</span> <span class="o">-</span> <span class="m">1</span> <span class="kr">else</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="n">y_vel</span> <span class="o">&lt;-</span> <span class="n">y_vel</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Retornar número de velocidades que funcionam</span>
</span></span><span class="line"><span class="cl"><span class="n">n_works</span></span></span></code></pre></div><h2 id="peixe-caracol-a">Peixe-Caracol (A)</h2>
<p>Chegou o <a href="https://adventofcode.com/2021/day/18">dia 18</a> do AoC e mais uma vez
o problema não foi muito difícil apesar do enunciado monstruoso. Uma coisa que
notei hoje é que havia vários caminhos para resolver o exercício que pareciam
igualmente razoáveis. No final eu decidi usar regex, uma das melhores e mais
temidas funcionalidades de qualquer linguagem de programação.</p>
<p>O enunciado pedia para aprendermos a fazer somas usando os números dos
peixes-caracol&hellip; A primeira característica desse sistema aritmético é que um
número é representado por pares de elementos na forma <code>[x,y]</code>, que podem ser
números normais ou outros pares; por exemplo <code>[[1,2],3]</code>. Além disso, há duas
limitações para os números: nunca pode haver um par dentro de 4 ou mais pares e
nenhum número normal pode ser maior que 9.</p>
<p>A soma dos peixes-caracol coloca cada um dos dois números como elementos de um
novo par. Se o primeiro número for <code>[a,b]</code> e o segundo <code>[x,y]</code>, então a soma
deles é <code>[[a,b],[x,y]]</code>. Obviamente isso pode criar um número que viola a
as limitações acima, então precisamos aplicar as regras da <em>explosão</em> e da
<em>quebra</em>. Abaixo eu descrevo as regras e as funções que criei para implementar
cada uma:</p>
<p>A regra da explosão sempre vem primeiro e ela deve ser aplicada o maior número
possível de vezes antes de partirmos para a regra da quebra.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Exemplo:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[4,[3,2]]]],1]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Passos da explosão:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1. Encontrar o primeiro par simples que está dentro de 4 ou mais pares</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [3,2]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Denominar as partes do par com x e y:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [x,y] = [3,2]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Somar x ao número normal mais próximo à esquerda (se houver)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[4 + 3,[3,2]]]],1]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[7,[3,2]]]],1]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 4. Somar y ao número normal mais próximo à direita (se houver)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[7,[3,2]]]],1 + 2]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[7,[3,2]]]],3]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 5. Substituir o par por 0</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6,[5,[7,0]]],3]</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Encontrar posição de um par que precisa ser explodido</span>
</span></span><span class="line"><span class="cl"><span class="n">find_explode</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">chrs</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span><span class="n">[[1]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos caracteres para encontrar um par profundo demais</span>
</span></span><span class="line"><span class="cl">  <span class="n">counter</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">chrs</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">chrs[i]</span> <span class="o">==</span> <span class="s">&#34;[&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">counter</span> <span class="o">&lt;-</span> <span class="n">counter</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">else</span> <span class="kr">if</span> <span class="p">(</span><span class="n">chrs[i]</span> <span class="o">==</span> <span class="s">&#34;]&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">counter</span> <span class="o">&lt;-</span> <span class="n">counter</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Se o par for profundo demais, retornar</span>
</span></span><span class="line"><span class="cl">      <span class="kr">if</span> <span class="p">(</span><span class="n">counter</span> <span class="o">&gt;=</span> <span class="m">4</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Encontrar o começo do par</span>
</span></span><span class="line"><span class="cl">        <span class="n">len</span> <span class="o">&lt;-</span> <span class="n">num</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">end</span> <span class="o">=</span> <span class="n">i</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;\\[[^\\[]*?$&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="n">stringr</span><span class="o">::</span><span class="nf">str_length</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="n">magrittr</span><span class="o">::</span><span class="nf">subtract</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Retornar &#34;coordenadas&#34; do par</span>
</span></span><span class="line"><span class="cl">        <span class="kr">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">i</span> <span class="o">-</span> <span class="n">len</span><span class="p">,</span> <span class="n">i</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Se não ouver par para explodir, returnar NULL</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="kc">NULL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar o algoritmo da explosão</span>
</span></span><span class="line"><span class="cl"><span class="n">explode</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar um par para explodir</span>
</span></span><span class="line"><span class="cl">  <span class="n">pos</span> <span class="o">&lt;-</span> <span class="nf">find_explode</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Se não houver par, retornar o número</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">pos</span><span class="p">))</span> <span class="kr">return</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Extrair números normais do par</span>
</span></span><span class="line"><span class="cl">  <span class="n">pair</span> <span class="o">&lt;-</span> <span class="n">num</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">pos[1]</span><span class="p">,</span> <span class="n">pos[2]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract_all</span><span class="p">(</span><span class="s">&#34;[0-9]+&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar a parte esquerda do número (até o par que vai explodir)</span>
</span></span><span class="line"><span class="cl">  <span class="n">lhs</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="n">pos[1]</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar o número normal mais próximo de pair[1] e somar</span>
</span></span><span class="line"><span class="cl">  <span class="n">left_num</span> <span class="o">&lt;-</span> <span class="n">lhs</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;[0-9]+(?=[^0-9]+$)&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">magrittr</span><span class="o">::</span><span class="nf">add</span><span class="p">(</span><span class="n">pair[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar a parte direita do número (a partir do par que vai explodir)</span>
</span></span><span class="line"><span class="cl">  <span class="n">rhs</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_sub</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">pos[2]</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar o número normal mais próximo de pair[2] e somar</span>
</span></span><span class="line"><span class="cl">  <span class="n">right_num</span> <span class="o">&lt;-</span> <span class="n">rhs</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;^[^0-9]+[0-9]+&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_remove</span><span class="p">(</span><span class="s">&#34;^[^0-9]+&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">magrittr</span><span class="o">::</span><span class="nf">add</span><span class="p">(</span><span class="n">pair[2]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Substituir os números normais que mudamos</span>
</span></span><span class="line"><span class="cl">  <span class="n">lhs</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="n">lhs</span><span class="p">,</span> <span class="s">&#34;[0-9]+([^0-9]+)$&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="n">left_num</span><span class="p">,</span> <span class="s">&#34;\\1&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="n">rhs</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="n">rhs</span><span class="p">,</span> <span class="s">&#34;^([^0-9]+)[0-9]+&#34;</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;\\1&#34;</span><span class="p">,</span> <span class="n">right_num</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Colar as partes esquerda e direita de volta</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="n">lhs</span><span class="p">,</span> <span class="s">&#34;0&#34;</span><span class="p">,</span> <span class="n">rhs</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Se não houver mais como aplicar a explosão, então podemos fazer uma quebra e
voltar para o começo do algoritmo: aplicar quantas explosões forem possíveis e
depois tentar uma quebra. Quando nenhuma regra puder ser aplicada, então
encontramos o resultado da soma.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Exemplo:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [11,1]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Passos da quebra:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1. Encontrar o primeiro número normal maior que 9</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 11</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Criar um novo par onde o elemento da esquerda é o número dividido por 2</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    arredondado para baixo e o elemento da direita é o número dividido por 2</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    arredondado para cima.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [5,6]</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Substituir o número normal pelo par criado</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[5,6],1]</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Aplicar o algoritmo da quebra</span>
</span></span><span class="line"><span class="cl"><span class="n">split</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Verificar se algo precisa ser quebrado e retornar o número se não</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="s">&#34;[0-9]{2,}&#34;</span><span class="p">))</span> <span class="kr">return</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar um par a partir das metades do primeiro número normal &gt; 9</span>
</span></span><span class="line"><span class="cl">  <span class="n">pair</span> <span class="o">&lt;-</span> <span class="n">num</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;[0-9]{2,}&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;[&#34;</span><span class="p">,</span> <span class="nf">floor</span><span class="p">(</span><span class="n">n</span> <span class="o">/</span> <span class="m">2</span><span class="p">),</span> <span class="s">&#34;,&#34;</span><span class="p">,</span> <span class="nf">ceiling</span><span class="p">(</span><span class="n">n</span> <span class="o">/</span> <span class="m">2</span><span class="p">),</span> <span class="s">&#34;]&#34;</span><span class="p">)}()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Substituir o número normal pelo par criado</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="s">&#34;[0-9]{2,}&#34;</span><span class="p">,</span> <span class="n">pair</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Agora que sabemos como explodir e qubrar, podemos implementar o algoritmo
completo da soma dos peixes-caracol. Notem o <code>next</code> no loop; ele é essencial
por causa da exigência de aplicarmos a explosão quantas vezes forem necessárias.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Soma dos peixes-caracol</span>
</span></span><span class="line"><span class="cl"><span class="n">snailfish_sum</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num1</span><span class="p">,</span> <span class="n">num2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Juntar números como elementos de um novo par</span>
</span></span><span class="line"><span class="cl">  <span class="n">num</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;[&#34;</span><span class="p">,</span> <span class="n">num1</span><span class="p">,</span> <span class="s">&#34;,&#34;</span><span class="p">,</span> <span class="n">num2</span><span class="p">,</span> <span class="s">&#34;]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aplicar explosão e quebra até o número não mudar mais</span>
</span></span><span class="line"><span class="cl">  <span class="n">num_</span> <span class="o">&lt;-</span> <span class="s">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">num_</span> <span class="o">!=</span> <span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">num_</span> <span class="o">&lt;-</span> <span class="n">num</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Explodir e, se o número tiver mudado, voltar</span>
</span></span><span class="line"><span class="cl">    <span class="n">num</span> <span class="o">&lt;-</span> <span class="nf">explode</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">num_</span> <span class="o">!=</span> <span class="n">num</span><span class="p">)</span> <span class="kr">next</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Qubrar</span>
</span></span><span class="line"><span class="cl">    <span class="n">num</span> <span class="o">&lt;-</span> <span class="nf">split</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Mas o enunciado não pedia para simplesmente implementarmos a soma dos
peixes-caracol&hellip; A resposta final deveria ser a magnitude do número obtido a
partir de somas sucessivas. Essencialmente, a nossa entrada era uma sequência
de números <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code>, etc. e devíamos calcular
<code>(((A + B) + C) + D) + ...</code>. Já a magnitude de um número envolve outro
algoritmo; a magnitude de um <code>[x,y]</code> qualquer é <code>3*x + 2*y</code>, mas devemos aplicar
isso recursivamente, entrando nas camadas mais profundas do número e voltando
para a superfície.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Fazer uma rodada do algoritmo da magnitude</span>
</span></span><span class="line"><span class="cl"><span class="n">get_one_magnitude</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar a magnitude do par mais à esquerda</span>
</span></span><span class="line"><span class="cl">  <span class="n">val</span> <span class="o">&lt;-</span> <span class="n">num</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;\\[[^\\[\\]]+\\]&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract_all</span><span class="p">(</span><span class="s">&#34;[0-9]+&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.numeric</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="m">3</span> <span class="o">*</span> <span class="n">n[1]</span> <span class="o">+</span> <span class="m">2</span> <span class="o">*</span> <span class="n">n[2]</span><span class="p">}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">as.character</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Trocar o par pela sua magnitude</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="s">&#34;\\[[^\\[\\]]+\\]&#34;</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar o algoritmo completo da magnitude</span>
</span></span><span class="line"><span class="cl"><span class="n">get_magnitude</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Enquanto ainda houver pares, fazer uma rodada do cálculo</span>
</span></span><span class="line"><span class="cl">  <span class="kr">while</span> <span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="s">&#34;\\[&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">num</span> <span class="o">&lt;-</span> <span class="nf">get_one_magnitude</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Retornar magnitude convertida para um valor numérico</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">num</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Enfim, depois de uma parede de texto e uma parede de código, podemos finalmente
juntar tudo na solução do primeiro item.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Reduce list of numbers with snalfish addition and get magnitude</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/18a_snailfish.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">reduce</span><span class="p">(</span><span class="n">snailfish_sum</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">get_magnitude</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 4124</span></span></span></code></pre></div><h2 id="peixes-caracol-b">Peixes-Caracol (B)</h2>
<p>Em um ato de bondade, o autor do Advent of Code fez um item 2 bem simples. Dados
todos os números <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code>, etc. que recebemos como entrada,
precisávamos combinar todos para encontrar a maior magnitude possível. Minha
solução foi gerar todas as somas possíveis (<code>A + B</code>, <code>B + A</code>, <code>A + C</code>, <code>C + A</code>,
etc., notando que <code>A + B != B + A</code>) e simplesmente calcular a magnitude de
todas. A resposta do item devia ser justamente essa maior magnitude possível.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Cruzar os números consigo mesmos e somar toda combinação</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;data-raw/18b_snailfish.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">ns</span><span class="p">)</span> <span class="nf">list</span><span class="p">(</span><span class="n">ns</span><span class="p">,</span> <span class="n">ns</span><span class="p">)}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">cross</span><span class="p">(</span><span class="n">`==`</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map_dbl</span><span class="p">(</span><span class="o">~</span><span class="nf">get_magnitude</span><span class="p">(</span><span class="nf">snailfish_sum</span><span class="p">(</span><span class="n">.x[[1]]</span><span class="p">,</span> <span class="n">.x[[2]]</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">max</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 4673</span></span></span></code></pre></div><h2 id="detectores-de-sinalizadores-a">Detectores de Sinalizadores (A)</h2>
<p>Neville Chamberlain tem uma frase que eu gosto muito: &ldquo;na guerra não há
vencedores, todos são perdedores.&rdquo; É assim que eu me senti com o
<a href="https://adventofcode.com/2021/day/19">dia 19</a> do AoC. No total eu demorei mais
de 6 horas de programação intensa para resolver o problema de hoje. Joguei meu
código fora múltiplas vezes, quase desisti, mas no final perseverei. Não acho
que eu tenha resolvido o problema; assim como Chamberlain, acredito que o
problema só perdeu antes.</p>
<p>Por esse motivo, o post de hoje vai ser um pouco diferente. Em primeiro lugar,
é impossível resumir as mais de 400 linhas do enunciado de forma efetiva e,
em segundo, explicar o raciocínio por trás da minha solução seria tão exaustivo
quanto. Sendo assim, vou fazer um super resumo do enunciado e deixar a
explicação do código a cargo dos comentários. Quem sabe um dia eu não revisito
esse exercício para dar um passo-a-passo melhor.</p>
<p>O grosso da pergunta é o seguinte: temos 36 detectores e uma série de
sinalizadores espalhados pelo oceano em posições fixas. A entrada são as
coordenadas dos sinalizadores que são vistos por cada detector relativas à
posição desse detector. Cada detector também pode estar em uma de 24 orientações
(olhando para +x com o topo apontado para +y, olhando para -y com o topo
apontado para +z, etc.). Se dois detectores tiverem uma intersecção entre os
seus cubos de detecção, então deve haver pelo menos 12 sinalizadores nesse
volume. A pergunta pede para calcularmos o número de sinalizadores que estão
nessa região do mar.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Converter c(x,y,z) para &#34;x,y,z&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">vec_to_str</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="n">vec</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;,&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Converter &#34;x,y,z&#34; para c(x,y,z)</span>
</span></span><span class="line"><span class="cl"><span class="n">str_to_vec</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">str</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.integer</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">str</span><span class="p">,</span> <span class="s">&#34;,&#34;</span><span class="p">)</span><span class="n">[[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Atalho para escolhe(n,2) de uma lista</span>
</span></span><span class="line"><span class="cl"><span class="n">choose_pairs</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">seq_along</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">seq_along</span><span class="p">(</span><span class="n">l</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">cross</span><span class="p">(</span><span class="n">`==`</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">transpose</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_int</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;a&#34;</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">rowwise</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">ordered</span> <span class="o">=</span> <span class="nf">paste0</span><span class="p">(</span><span class="nf">sort</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)),</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;,&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">ordered</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">slice_head</span><span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">ungroup</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">ordered</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">a</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="o">~</span><span class="n">l[[.x]]</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="n">b</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="o">~</span><span class="n">l[[.x]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar todas as rotações de um ponto</span>
</span></span><span class="line"><span class="cl"><span class="n">apply_rotations</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">point</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">rotations</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">0</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">),</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar uma tabela com (x, y, z) rotacionados e um ID de rotação</span>
</span></span><span class="line"><span class="cl">  <span class="n">rotations</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">map</span><span class="p">,</span> <span class="n">`*`</span><span class="p">,</span> <span class="n">point</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">map</span><span class="p">,</span> <span class="n">sum</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_dbl</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;point&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">rotation</span> <span class="o">=</span> <span class="n">rotations</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tibble</span><span class="o">::</span><span class="nf">rowid_to_column</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">point</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">coord</span> <span class="o">=</span> <span class="nf">rep</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s">&#34;x&#34;</span><span class="p">,</span> <span class="s">&#34;y&#34;</span><span class="p">,</span> <span class="s">&#34;z&#34;</span><span class="p">),</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">n</span><span class="p">()</span> <span class="o">/</span> <span class="m">3</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tidyr</span><span class="o">::</span><span class="nf">pivot_wider</span><span class="p">(</span><span class="n">names_from</span> <span class="o">=</span> <span class="n">coord</span><span class="p">,</span> <span class="n">values_from</span> <span class="o">=</span> <span class="n">point</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">rotation</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">rotation</span><span class="p">,</span> <span class="n">paste</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;,&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">rotation</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Fábrica de função para transformar um ponto com rotação + translação</span>
</span></span><span class="line"><span class="cl"><span class="n">factory_transform</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Extrair a operação de rotação da df</span>
</span></span><span class="line"><span class="cl">  <span class="n">rot</span> <span class="o">&lt;-</span> <span class="n">df</span><span class="o">$</span><span class="n">rotation</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;c\\(&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_remove</span><span class="p">(</span><span class="s">&#34;\\),?&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_subset</span><span class="p">(</span><span class="s">&#34;,&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;, &#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">as.numeric</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Extrair a operação de translação da df</span>
</span></span><span class="line"><span class="cl">  <span class="n">trans</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">dif_x</span><span class="p">,</span> <span class="n">df</span><span class="o">$</span><span class="n">dif_y</span><span class="p">,</span> <span class="n">df</span><span class="o">$</span><span class="n">dif_z</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Retornar função que aplica a transformação</span>
</span></span><span class="line"><span class="cl">  <span class="kr">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">rot</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">`*`</span><span class="p">,</span> <span class="n">vec</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_dbl</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">magrittr</span><span class="o">::</span><span class="nf">add</span><span class="p">(</span><span class="n">trans</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar todas as intersecções entre detectores</span>
</span></span><span class="line"><span class="cl"><span class="n">get_intersections</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">points</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Parear os detectores e retornar as suas intersecções</span>
</span></span><span class="line"><span class="cl">  <span class="n">points</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">choose_pairs</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">,</span> <span class="c1"># Intersecções são baseadas nas distâncias entre pontos</span>
</span></span><span class="line"><span class="cl">      <span class="n">dist</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2_dbl</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">~</span><span class="nf">sum</span><span class="p">((</span><span class="n">.x</span> <span class="o">-</span> <span class="n">.y</span><span class="p">)</span><span class="o">**</span><span class="m">2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">choose_pairs</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">rowwise</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_split</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">inner_join</span><span class="p">(</span><span class="n">.x[[</span><span class="s">&#34;a&#34;</span><span class="n">]][[1]]</span><span class="p">,</span> <span class="n">.x[[</span><span class="s">&#34;b&#34;</span><span class="n">]][[1]]</span><span class="p">,</span> <span class="s">&#34;dist&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">keep</span><span class="p">(</span><span class="o">~</span><span class="nf">nrow</span><span class="p">(</span><span class="n">.x</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="m">66</span><span class="p">)</span> <span class="c1"># 66 = C(12, 2) = 12 pontos na intersec.</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar todas as transformações que podem converter pairs1 em pairs2</span>
</span></span><span class="line"><span class="cl"><span class="n">get_transforms</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">pairs1</span><span class="p">,</span> <span class="n">pairs2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar uma função que leva pairs1[2] a pairs2[2a] ou pairs2[2b]</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="nf">apply_rotations</span><span class="p">(</span><span class="n">pairs1</span><span class="o">$</span><span class="n">a.x[[2]]</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_x</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">a.y[[2]][1]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_y</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">a.y[[2]][2]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_z</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">a.y[[2]][3]</span>
</span></span><span class="line"><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="nf">apply_rotations</span><span class="p">(</span><span class="n">pairs1</span><span class="o">$</span><span class="n">a.x[[2]]</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_x</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">b.y[[2]][1]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_y</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">b.y[[2]][2]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">ref_z</span> <span class="o">=</span> <span class="n">pairs2</span><span class="o">$</span><span class="n">b.y[[2]][3]</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">dif_x</span> <span class="o">=</span> <span class="n">ref_x</span> <span class="o">-</span> <span class="n">x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">dif_y</span> <span class="o">=</span> <span class="n">ref_y</span> <span class="o">-</span> <span class="n">y</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">dif_z</span> <span class="o">=</span> <span class="n">ref_z</span> <span class="o">-</span> <span class="n">z</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">rowwise</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_split</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">factory_transform</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Encontrar a função correta de transformação</span>
</span></span><span class="line"><span class="cl"><span class="n">find_transform</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">funs</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Dadas as funções de transformação, encontrar uma que converte os pontos de</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># df (conjunto de intersecções) corretamente</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tibble</span><span class="o">::</span><span class="nf">rowid_to_column</span><span class="p">(</span><span class="s">&#34;pair_id&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">rowwise</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_split</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">.x</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(,</span>
</span></span><span class="line"><span class="cl">          <span class="n">fun_a.x</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">funs</span><span class="p">,</span> <span class="o">~</span><span class="nf">.x</span><span class="p">(</span><span class="n">a.x[[1]]</span><span class="p">))),</span>
</span></span><span class="line"><span class="cl">          <span class="n">fun_id</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">seq_along</span><span class="p">(</span><span class="n">funs</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">starts_with</span><span class="p">(</span><span class="s">&#34;fun&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">dist</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">tidyr</span><span class="o">::</span><span class="nf">unnest</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">everything</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">bind_rows</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">a_works</span> <span class="o">=</span> <span class="n">a.y</span> <span class="o">==</span> <span class="n">fun_a.x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">b_works</span> <span class="o">=</span> <span class="n">b.y</span> <span class="o">==</span> <span class="n">fun_a.x</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">pair_id</span><span class="p">,</span> <span class="n">fun_id</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="n">some_works</span> <span class="o">=</span> <span class="nf">all</span><span class="p">(</span><span class="n">a_works</span><span class="p">)</span> <span class="o">||</span> <span class="nf">all</span><span class="p">(</span><span class="n">b_works</span><span class="p">),</span> <span class="n">.groups</span> <span class="o">=</span> <span class="s">&#34;drop&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">ungroup</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_by</span><span class="p">(</span><span class="n">fun_id</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">summarise</span><span class="p">(</span><span class="n">works</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">some_works</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">slice_max</span><span class="p">(</span><span class="n">works</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">fun_id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler pontos como uma lista de vetores</span>
</span></span><span class="line"><span class="cl"><span class="n">points</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/19a_beacon_scanner.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;point&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">scanner</span> <span class="o">=</span> <span class="nf">as.integer</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">point</span><span class="p">,</span> <span class="s">&#34;scanner&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="n">scanner</span> <span class="o">=</span> <span class="nf">cumsum</span><span class="p">(</span><span class="n">scanner</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="o">!</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">point</span><span class="p">,</span> <span class="s">&#34;scanner&#34;</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">point</span> <span class="o">!=</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">group_split</span><span class="p">(</span><span class="n">scanner</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="n">pull</span><span class="p">,</span> <span class="n">point</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">map</span><span class="p">,</span> <span class="n">str_to_vec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Reduzir detectores a uma única região</span>
</span></span><span class="line"><span class="cl"><span class="kr">while</span> <span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">points</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar um par de detectores que tem uma intersecção</span>
</span></span><span class="line"><span class="cl">  <span class="n">pairs</span> <span class="o">&lt;-</span> <span class="nf">get_intersections</span><span class="p">(</span><span class="n">points</span><span class="p">)</span><span class="n">[[1]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar todas as funções de transformação</span>
</span></span><span class="line"><span class="cl">  <span class="n">funs</span> <span class="o">&lt;-</span> <span class="nf">get_transforms</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">a.x</span><span class="p">,</span> <span class="n">b.x</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">a.y</span><span class="p">,</span> <span class="n">b.y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar a função correta</span>
</span></span><span class="line"><span class="cl">  <span class="n">transformation</span> <span class="o">&lt;-</span> <span class="n">funs[</span><span class="nf">[find_transform</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">funs</span><span class="p">)</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Converter pontos para strings</span>
</span></span><span class="line"><span class="cl">  <span class="n">pairs</span> <span class="o">&lt;-</span> <span class="n">pairs</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">dist</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">map_chr</span><span class="p">,</span> <span class="n">vec_to_str</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar uma cópia dos pontos que também é strings</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="n">map_chr</span><span class="p">,</span> <span class="n">vec_to_str</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar detector usado como referência por transformation()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">points_</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ref</span> <span class="o">&lt;-</span> <span class="nf">all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">pairs</span><span class="o">$</span><span class="n">a.y</span><span class="p">,</span> <span class="n">pairs</span><span class="o">$</span><span class="n">b.y</span><span class="p">)</span> <span class="o">%in%</span> <span class="n">points_[[i]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">ref</span><span class="p">)</span> <span class="n">reference</span> <span class="o">&lt;-</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar detector que foi transformado por transformation()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">points_</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">trns</span> <span class="o">&lt;-</span> <span class="nf">all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">pairs</span><span class="o">$</span><span class="n">a.x</span><span class="p">,</span> <span class="n">pairs</span><span class="o">$</span><span class="n">b.x</span><span class="p">)</span> <span class="o">%in%</span> <span class="n">points_[[i]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">trns</span><span class="p">)</span> <span class="n">transformed</span> <span class="o">&lt;-</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aplicar transformation() em todos os pontos do detector e adicionar pontos</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># transformados ao detector de referência</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_[[reference]]</span> <span class="o">&lt;-</span> <span class="n">points[[transformed]]</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">transformation</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">vec_to_str</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">c</span><span class="p">(</span><span class="n">points_[[reference]]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">unique</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar lista de pontos</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_[[transformed]]</span> <span class="o">&lt;-</span> <span class="kc">NULL</span>
</span></span><span class="line"><span class="cl">  <span class="n">points</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">points_</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="n">map</span><span class="p">,</span> <span class="n">str_to_vec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Calcular o número de pontos em uma única região contígua</span>
</span></span><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="nf">lengths</span><span class="p">(</span><span class="n">points</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 408</span></span></span></code></pre></div><h2 id="detectores-de-sinalizadores-b">Detectores de Sinalizadores (B)</h2>
<p>O segundo item pedia para que encontrássemos a maior
<a href="https://pt.wikipedia.org/wiki/Geometria_do_t%C3%A1xi">distância de Manhattan</a>
entre detectores distintos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Reduzir detectores a uma única região, guardando as funções de tranform.</span>
</span></span><span class="line"><span class="cl"><span class="n">save_funs</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">while</span> <span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">points</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar um par de detectores que tem uma intersecção</span>
</span></span><span class="line"><span class="cl">  <span class="n">pairs</span> <span class="o">&lt;-</span> <span class="nf">get_intersections</span><span class="p">(</span><span class="n">points</span><span class="p">)</span><span class="n">[[1]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pegar todas as funções de transformação</span>
</span></span><span class="line"><span class="cl">  <span class="n">funs</span> <span class="o">&lt;-</span> <span class="nf">get_transforms</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">a.x</span><span class="p">,</span> <span class="n">b.x</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">a.y</span><span class="p">,</span> <span class="n">b.y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar a função correta</span>
</span></span><span class="line"><span class="cl">  <span class="n">transformation</span> <span class="o">&lt;-</span> <span class="n">funs[</span><span class="nf">[find_transform</span><span class="p">(</span><span class="n">pairs</span><span class="p">,</span> <span class="n">funs</span><span class="p">)</span><span class="n">]]</span>
</span></span><span class="line"><span class="cl">  <span class="n">save_funs</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="n">save_funs</span><span class="p">,</span> <span class="n">transformation</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Converter pontos para strings</span>
</span></span><span class="line"><span class="cl">  <span class="n">pairs</span> <span class="o">&lt;-</span> <span class="n">pairs</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">dist</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate_all</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">map_chr</span><span class="p">,</span> <span class="n">vec_to_str</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar uma cópia dos pontos que também é strings</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="n">map_chr</span><span class="p">,</span> <span class="n">vec_to_str</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar detector usado como referência por transformation()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">points_</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ref</span> <span class="o">&lt;-</span> <span class="nf">all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">pairs</span><span class="o">$</span><span class="n">a.y</span><span class="p">,</span> <span class="n">pairs</span><span class="o">$</span><span class="n">b.y</span><span class="p">)</span> <span class="o">%in%</span> <span class="n">points_[[i]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">ref</span><span class="p">)</span> <span class="n">reference</span> <span class="o">&lt;-</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Encontrar detector que foi transformado por transformation()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">points_</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">trns</span> <span class="o">&lt;-</span> <span class="nf">all</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">pairs</span><span class="o">$</span><span class="n">a.x</span><span class="p">,</span> <span class="n">pairs</span><span class="o">$</span><span class="n">b.x</span><span class="p">)</span> <span class="o">%in%</span> <span class="n">points_[[i]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">trns</span><span class="p">)</span> <span class="n">transformed</span> <span class="o">&lt;-</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Aplicar transformation() em todos os pontos do detector e adicionar pontos</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># transformados ao detector de referência</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_[[reference]]</span> <span class="o">&lt;-</span> <span class="n">points[[transformed]]</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">transformation</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">vec_to_str</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">c</span><span class="p">(</span><span class="n">points_[[reference]]</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">unique</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar lista de pontos</span>
</span></span><span class="line"><span class="cl">  <span class="n">points_[[transformed]]</span> <span class="o">&lt;-</span> <span class="kc">NULL</span>
</span></span><span class="line"><span class="cl">  <span class="n">points</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">points_</span><span class="p">,</span> <span class="n">purrr</span><span class="o">::</span><span class="n">map</span><span class="p">,</span> <span class="n">str_to_vec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar transformações aos detectores e tirar distância de Manhattan</span>
</span></span><span class="line"><span class="cl"><span class="n">save_funs</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">.x</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">choose_pairs</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span><span class="n">dist</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2_dbl</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">~</span><span class="nf">sum</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">.x</span> <span class="o">-</span> <span class="n">.y</span><span class="p">))))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">slice_max</span><span class="p">(</span><span class="n">dist</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">pull</span><span class="p">(</span><span class="n">dist</span><span class="p">)</span></span></span></code></pre></div><h2 id="mapa-da-fossa-a">Mapa da Fossa (A)</h2>
<p>Depois de um domingo assustadoramente difícil, o problema do
<a href="https://adventofcode.com/2021/day/20">dia 20</a> do AoC foi bastante tranquilo de
resolver. Tanto o enunciado quanto a solução me pareceram simples (apesar de
algumas reclamações na internet sobre uma pegadinha que vou explicar em breve).</p>
<p>Hoje nós recebemos uma imagem na forma de uma matriz composta por pontos
luminosos <code>#</code> e pontos escuros <code>.</code>. O outro componente da entrada era uma lista
de &ldquo;conversões&rdquo;: nós deveríamos converter cada quadrado 3x3 da imagem em um
número binário onde <code># = 1</code> e <code>. = 0</code> e encontrar o elemento de índice
correspondente da lista de conversões; o ponto do centro do quadrado deveria ser
substituido por esse elemento da lista.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Um quadrado 3x3</span>
</span></span><span class="line"><span class="cl"><span class="c1"># # . . # .</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #[. . .].</span>
</span></span><span class="line"><span class="cl"><span class="c1"># #[# . .]#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .[. # .].</span>
</span></span><span class="line"><span class="cl"><span class="c1"># . . # # #</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Número correspondente</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...#...#. = 000100010 = 34</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 34o elemento da lista de conversões</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 0         10        20        30 [34]   40        50        60        70</span>
</span></span><span class="line"><span class="cl"><span class="c1"># |         |         |         |   |     |         |         |         |</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..##</span></span></span></code></pre></div><p>Entretanto, essa operação, denominada <em>realce</em>, tinha um detalhe a mais. A nossa
imagem de entrada era, na verdade, infinita! Em todas as direções, a imagem
deveria ser completa por infinitos pontos escuros. Nosso objetivo era contar o
número de pontos luminosos que restavam na nossa imagem após 2 aplicações do
realce.</p>
<p>Como é possível imaginar, os pontos escuros infinitos não podem fazer diferença
nessa contagem (senão a resposta seria incalculável). Note que um quadrado
composto só por pontos escuros equivale ao índice 0 da lista e, no exemplo
acima, isso é convertido para um novo ponto escuro; ou seja, as bordas infinitas
continuam sendo escuras após o realce.</p>
<p>A pegadinha, porém, era que a lista de conversões na entrada do problema
começava com <code>#</code> e não <code>.</code>, ou seja, os infinitos pontos escuros iam virar
infinitos pontos luminosos depois de um realce. Felizmente, na segunda
aplicação, todos os quadrados luminosos apontariam para o 511º elemento da lista
e esse sim era um <code>.</code>. Em conclusão, desde que aplicássemos um número par de
realces, as fronteiras infinitas da imagem seriam escuras e o número de pontos
luminosos poderia ser contado.</p>
<p>Sendo assim, o código que resolvia o problema era bem simples, bastava adicionar
uma borda escura à imagem para levar em conta a fronteira infinita e seguir em
frente.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Converter uma região 3x3 em um número</span>
</span></span><span class="line"><span class="cl"><span class="n">img_to_int</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Achatar a matriz para uma só coluna</span>
</span></span><span class="line"><span class="cl">  <span class="n">bits</span> <span class="o">&lt;-</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">image</span> <span class="o">==</span> <span class="s">&#34;.&#34;</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">binary</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="nf">as.vector</span><span class="p">(</span><span class="nf">t</span><span class="p">(</span><span class="n">bits</span><span class="p">)),</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># String para inteiro</span>
</span></span><span class="line"><span class="cl">  <span class="nf">strtoi</span><span class="p">(</span><span class="n">binary</span><span class="p">,</span> <span class="n">base</span> <span class="o">=</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar realce</span>
</span></span><span class="line"><span class="cl"><span class="n">enhance</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">algo</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nas linhas e colunas, sem passar pela borda</span>
</span></span><span class="line"><span class="cl">  <span class="n">new_image</span> <span class="o">&lt;-</span> <span class="n">image</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="p">(</span><span class="nf">ncol</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1"># Trocar [i,j] pelo índice correspondente em `algo`</span>
</span></span><span class="line"><span class="cl">      <span class="n">ind</span> <span class="o">&lt;-</span> <span class="nf">img_to_int</span><span class="p">(</span><span class="n">image</span><span class="nf">[</span><span class="p">(</span><span class="m">-1</span><span class="o">:</span><span class="m">1</span> <span class="o">+</span> <span class="n">i</span><span class="p">),</span> <span class="p">(</span><span class="m">-1</span><span class="o">:</span><span class="m">1</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">new_image[i</span><span class="p">,</span> <span class="n">j]</span> <span class="o">&lt;-</span> <span class="n">algo[ind</span> <span class="o">+</span> <span class="m">1</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Remover borda e retornar</span>
</span></span><span class="line"><span class="cl">  <span class="n">new_image[2</span><span class="o">:</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">),</span> <span class="m">2</span><span class="o">:</span><span class="p">(</span><span class="nf">ncol</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Adicionar borda</span>
</span></span><span class="line"><span class="cl"><span class="n">add_padding</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">image</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar mais 2 linhas em cima e embaixo</span>
</span></span><span class="line"><span class="cl">  <span class="n">image</span> <span class="o">&lt;-</span> <span class="nf">rbind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">image[1</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span> <span class="n">image[1</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">image</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">image</span><span class="nf">[nrow</span><span class="p">(</span><span class="n">image</span><span class="p">),</span> <span class="n">]</span><span class="p">,</span> <span class="n">image</span><span class="nf">[nrow</span><span class="p">(</span><span class="n">image</span><span class="p">),</span> <span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar 2 colunas na esquerda e na direita</span>
</span></span><span class="line"><span class="cl">  <span class="n">image</span> <span class="o">&lt;-</span> <span class="nf">cbind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">image[</span><span class="p">,</span> <span class="m">1</span><span class="n">]</span><span class="p">,</span> <span class="n">image[</span><span class="p">,</span> <span class="m">1</span><span class="n">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">image</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">image[</span><span class="p">,</span> <span class="nf">ncol</span><span class="p">(</span><span class="n">image</span><span class="p">)</span><span class="n">]</span><span class="p">,</span> <span class="n">image[</span><span class="p">,</span> <span class="nf">ncol</span><span class="p">(</span><span class="n">image</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler lista de realce como um vetor de strings</span>
</span></span><span class="line"><span class="cl"><span class="n">algo</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/20a_trench_map.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">pluck</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler imagem como uma matriz (e adicionar bordas)</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/20a_trench_map.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">(</span><span class="n">skip</span> <span class="o">=</span> <span class="m">2</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">prepend</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">,</span> <span class="m">100</span><span class="p">),</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">),</span> <span class="m">3</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">append</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">,</span> <span class="m">100</span><span class="p">),</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">),</span> <span class="m">3</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="nf">\</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="s">&#34;...&#34;</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="s">&#34;...&#34;</span><span class="p">)}()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">matrix</span><span class="p">(</span><span class="m">106</span><span class="p">,</span> <span class="m">106</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Aplicar o realce duas vezes e contar pontos luminosos</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">enhance</span><span class="p">(</span><span class="n">algo</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">add_padding</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">enhance</span><span class="p">(</span><span class="n">algo</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">magrittr</span><span class="o">::</span><span class="nf">equals</span><span class="p">(</span><span class="s">&#34;#&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 5498</span></span></span></code></pre></div><h2 id="mapa-da-fossa-b">Mapa da Fossa (B)</h2>
<p>O segundo item pedia apenas para aplicarmos o algoritmo 50 ao invés de 2 vezes e
contar o número de pontos luminosos. Como o nosso algoritmo generaliza as
bordas, podemos simplesmente aplicá-lo mais vezes.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Aplicar o realce 50 vezes</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">&lt;-</span> <span class="nf">enhance</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">algo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="m">49</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">image</span> <span class="o">&lt;-</span> <span class="nf">enhance</span><span class="p">(</span><span class="nf">add_padding</span><span class="p">(</span><span class="n">image</span><span class="p">),</span> <span class="n">algo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contar pontos luminosos</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">magrittr</span><span class="o">::</span><span class="nf">equals</span><span class="p">(</span><span class="s">&#34;#&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 16014</span></span></span></code></pre></div><h2 id="dados-de-dirac-a">Dados de Dirac (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/21">dia 21</a> do AoC começou bem. O primeiro
item foi bastante direto e tranquilo&hellip; O que complicou tudo foi o segundo.</p>
<p>Começamos aprendendo as regras de um jogo chamado Dados de Dirac. Ele é composto
um tabuleiro circular que vai de 1 a 10, um dado e dois peões para representar
os dois jogadores. Cada jogador rola o dado 3 vezes, soma os resultados e anda
aquele número de casas no tabuleiro; o número da casa em que ele caiu é então
adicionado à pontuação do jogador. Cada jogador começa em uma casa escolhida
aleatoriamente e ganha o primeiro a atingir 1000 ou mais pontos.</p>
<p>O primeiro item pedia para simularmos um jogo de Dados de Dirac com um dado
determinístico antes de partirmos para a versão oficial. Nós recebemos como
entrada a posição de início de cada jogador e a mecânica de funcionamento do
dado: ele ia de 1 a 100 e seu resultado sempre vinha nessa ordem (ou seja, o
primeiro jogador rolaria 1, 2, 3, o segundo rolaria 4, 5, 6, etc.). Nosso
objetivo era simular o jogo até que alguém ganhasse e retornar a pontuação do
jogador perdedor multiplicada pelo número de vezes que o dado foi rolado naquele
jogo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler posições iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">pos</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/21a_dirac_dice.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;[0-9]+$&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.numeric</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Posições iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">p1_pos</span> <span class="o">&lt;-</span> <span class="n">pos[1]</span>
</span></span><span class="line"><span class="cl"><span class="n">p2_pos</span> <span class="o">&lt;-</span> <span class="n">pos[2]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pontuações iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">p1_pts</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="n">p2_pts</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Fazer os dados irem do valor máximo para 1</span>
</span></span><span class="line"><span class="cl"><span class="n">die_mod</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span><span class="p">)</span> <span class="p">((</span><span class="n">e1</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span> <span class="o">%%</span> <span class="n">e2</span><span class="p">)</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar até o jogo acabar</span>
</span></span><span class="line"><span class="cl"><span class="n">die</span> <span class="o">&lt;-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="n">counter</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">while</span> <span class="p">(</span><span class="kc">TRUE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># J1 rola 3 vezes</span>
</span></span><span class="line"><span class="cl">  <span class="n">p1_rolls</span> <span class="o">&lt;-</span> <span class="n">die</span><span class="o">:</span><span class="p">(</span><span class="n">die</span> <span class="o">+</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p1_rolls</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p1_rolls</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar estado do dado e contador de rolagem</span>
</span></span><span class="line"><span class="cl">  <span class="n">die</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p1_rolls[3]</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">counter</span> <span class="o">&lt;-</span> <span class="n">counter</span> <span class="o">+</span> <span class="m">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar pontuação do J1</span>
</span></span><span class="line"><span class="cl">  <span class="n">p1_pos</span> <span class="o">&lt;-</span> <span class="n">p1_pos</span> <span class="o">+</span> <span class="nf">sum</span><span class="p">(</span><span class="n">p1_rolls</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p1_pos</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p1_pos</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p1_pts</span> <span class="o">&lt;-</span> <span class="n">p1_pts</span> <span class="o">+</span> <span class="n">p1_pos</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Parar se J1 ganhou</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">p1_pts</span> <span class="o">&gt;=</span> <span class="m">1000</span><span class="p">)</span> <span class="kr">break</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># J2 rola 3 vezes</span>
</span></span><span class="line"><span class="cl">  <span class="n">p2_rolls</span> <span class="o">&lt;-</span> <span class="n">die</span><span class="o">:</span><span class="p">(</span><span class="n">die</span> <span class="o">+</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p2_rolls</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p2_rolls</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar estado do dado e contador de rolagem</span>
</span></span><span class="line"><span class="cl">  <span class="n">die</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p2_rolls[3]</span> <span class="o">+</span> <span class="m">1</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">counter</span> <span class="o">&lt;-</span> <span class="n">counter</span> <span class="o">+</span> <span class="m">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar pontuação do J2</span>
</span></span><span class="line"><span class="cl">  <span class="n">p2_pos</span> <span class="o">&lt;-</span> <span class="n">p2_pos</span> <span class="o">+</span> <span class="nf">sum</span><span class="p">(</span><span class="n">p2_rolls</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p2_pos</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p2_pos</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p2_pts</span> <span class="o">&lt;-</span> <span class="n">p2_pts</span> <span class="o">+</span> <span class="n">p2_pos</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Parar se J2 ganhou</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">p2_pts</span> <span class="o">&gt;=</span> <span class="m">1000</span><span class="p">)</span> <span class="kr">break</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contador * pontuação do perdedor</span>
</span></span><span class="line"><span class="cl"><span class="nf">min</span><span class="p">(</span><span class="n">p1_pts</span><span class="p">,</span> <span class="n">p2_pts</span><span class="p">)</span> <span class="o">*</span> <span class="n">counter</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 597600</span></span></span></code></pre></div><h2 id="dados-de-dirac-b">Dados de Dirac (B)</h2>
<p>Bem direto, certo? Uma pena que o segundo item não tinha nada a ver&hellip; Agora
deveríamos simular o jogo com o epônimo Dado de Dirac. Ele tem 3 lados (de 1 a
3) e, cada vez que ele é rolado, um universo paralelo é criado para cada
possível resultado. Em suma, no final do jogo haveria um universo para cada
caminho que o jogo poderia hipoteticamente tomar. Felizmente, com o Dado de
Dirac, o jogo ia só até 21 pontos.</p>
<p>Nossa missão era, dadas as posições iniciais, calcular em quantos universos
ganhava o jogador que ganhava mais vezes. Não parece tão difícil até você
perceber que teremos algo em torno de 700 <em>trilhões</em> de universos para
considerar. Espero que esteja claro que tentar gerar todas as rodadas não vai
funcionar.</p>
<p>A solução ideal para esse problema é
<a href="https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_din%C3%A2mica">programação dinâmica</a>
(PD) que, apesar do nome esotérico, não é tão misteriosa assim. De forma bem
superficial, um algoritmo que usa PD começa dividindo o problema principal em
sub-problemas mais simples e armazenando seus resultados; a parte vital é,
então, utilizar esses resultados já calculados para evitar contas desnecessárias
mais para frente.</p>
<p>Concretamente, queremos dividir o jogo em estados distintos definidos pelos
quartetos <code>(p1_pos, p2_pos, p1_pts, p2_pts)</code>. Vejamos como funcionaria um trecho
desse algoritmo:</p>
<ol>
<li>
<p>Começamos por um estado no final do jogo: <code>(3, 8, 19, 21)</code>. Neste universo,
sabemos que o J2 ganhou, então salvamos a informação <code>(3, 8, 19, 21) = (0, 1)</code>.</p>
</li>
<li>
<p>Mais para frente, encontramos o estado <code>(3, 5, 19, 13)</code>. O J2 pode rolar uma
série de valores aqui que precisamos verificar, mas, se ele rolar 1 + 1 + 1,
sabemos que cairemos no estado <code>(3, 8, 19, 21)</code>! Sendo assim, podemos pular este
cálculo e verificar apenas as outras rolagens possíveis.</p>
</li>
<li>
<p>Com PD, calcularemos primeiro estados mais fáceis e, conforme formos
evoluindo para o começo do jogo, já teremos calculado o número de vitórias de
cada jogador em cada futuro. Assim, basta somar esses futuros e passar para um
estado anterior.</p>
</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler posições iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">pos</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/21b_dirac_dice.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;[0-9]+$&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.numeric</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Posições iniciais</span>
</span></span><span class="line"><span class="cl"><span class="n">p1_pos</span> <span class="o">&lt;-</span> <span class="n">pos[1]</span>
</span></span><span class="line"><span class="cl"><span class="n">p2_pos</span> <span class="o">&lt;-</span> <span class="n">pos[2]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Fazer os dados irem do valor máximo para 1</span>
</span></span><span class="line"><span class="cl"><span class="n">die_mod</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span><span class="p">)</span> <span class="p">((</span><span class="n">e1</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span> <span class="o">%%</span> <span class="n">e2</span><span class="p">)</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Criar um identificar para `states`</span>
</span></span><span class="line"><span class="cl"><span class="n">id</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">)</span> <span class="nf">paste0</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="s">&#34;,&#34;</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="s">&#34;,&#34;</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="s">&#34;,&#34;</span><span class="p">,</span> <span class="n">d</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contar vitórias de cada jogador a partir de cada estado do jogo</span>
</span></span><span class="line"><span class="cl"><span class="n">states</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">count_states</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">p1_pos</span><span class="p">,</span> <span class="n">p2_pos</span><span class="p">,</span> <span class="n">p1_pts</span> <span class="o">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">p2_pts</span> <span class="o">=</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">this_id</span> <span class="o">&lt;-</span> <span class="nf">id</span><span class="p">(</span><span class="n">p1_pos</span><span class="p">,</span> <span class="n">p2_pos</span><span class="p">,</span> <span class="n">p1_pts</span><span class="p">,</span> <span class="n">p2_pts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Condições de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">p1_pts</span> <span class="o">&gt;=</span> <span class="m">21</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">p2_pts</span> <span class="o">&gt;=</span> <span class="m">21</span><span class="p">)</span> <span class="kr">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">this_id</span> <span class="o">%in%</span> <span class="nf">names</span><span class="p">(</span><span class="n">states</span><span class="p">))</span> <span class="kr">return</span><span class="p">(</span><span class="n">states[[this_id]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Todas as combinações possíveis de rolagens</span>
</span></span><span class="line"><span class="cl">  <span class="n">rolls</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">cross</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_int</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">purrr</span><span class="o">::</span><span class="nf">map_int</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nas rolagens e fazer a recursão para os próximos estados</span>
</span></span><span class="line"><span class="cl">  <span class="n">wins_total</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">roll</span> <span class="kr">in</span> <span class="n">rolls</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">p1_pos_</span> <span class="o">&lt;-</span> <span class="nf">die_mod</span><span class="p">(</span><span class="n">p1_pos</span> <span class="o">+</span> <span class="n">roll</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Ir para o próximo estado e somar vitórias</span>
</span></span><span class="line"><span class="cl">    <span class="n">wins</span> <span class="o">&lt;-</span> <span class="nf">count_states</span><span class="p">(</span><span class="n">p2_pos</span><span class="p">,</span> <span class="n">p1_pos_</span><span class="p">,</span> <span class="n">p2_pts</span><span class="p">,</span> <span class="n">p1_pts</span> <span class="o">+</span> <span class="n">p1_pos_</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">wins_total</span> <span class="o">&lt;-</span> <span class="n">wins_total</span> <span class="o">+</span> <span class="nf">rev</span><span class="p">(</span><span class="n">wins</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atualizar `states` e retornar</span>
</span></span><span class="line"><span class="cl">  <span class="n">states[[this_id]]</span> <span class="o">&lt;&lt;-</span> <span class="n">wins_total</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">wins_total</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rodar programação dinâmica</span>
</span></span><span class="line"><span class="cl"><span class="nf">count_states</span><span class="p">(</span><span class="n">p1_pos</span><span class="p">,</span> <span class="n">p2_pos</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">max</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">format</span><span class="p">(</span><span class="n">scientific</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 634769613696613</span></span></span></code></pre></div><h2 id="reinicialização-do-reator-a">Reinicialização do Reator (A)</h2>
<p>O <a href="https://adventofcode.com/2021/day/22">dia 22</a> do AoC foi mais um cujo
enunciado não apresentou dificuldades. Não que a resolução tenha sido fácil, mas
pelo menos o problema foi fácil de entender.</p>
<p>Essencialmente tínhamos que reiniciar o reator do submarino seguindo uma série
de instruções (a entrada do problema). O reator era composto por uma grade
gigantesca feita de cubos 1x1x1 que começavam todos desligados; cada instrução
nos dava uma região do reator que precisava ser desligada ou ligada:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># on x=10..12,y=10..12,z=10..12</span>
</span></span><span class="line"><span class="cl"><span class="c1"># on x=11..13,y=11..13,z=11..13</span>
</span></span><span class="line"><span class="cl"><span class="c1"># off x=9..11,y=9..11,z=9..11</span>
</span></span><span class="line"><span class="cl"><span class="c1"># on x=10..10,y=10..10,z=10..10</span></span></span></code></pre></div><p>O primeiro comando da lista acima, por exemplo, ligava todos os cubos dentro da
matrix <code>reator[10:12, 10:12, 10:12]</code>. Nosso objetivo no primeiro item era contar
todos os cubos que estariam acessos no final do processo de reinicialização, mas
levando em conta <em>apenas</em> os cubos dentro da região denotada por
<code>x=-50..50,y=-50..50,z=-50..50</code>.</p>
<p>O código era bastante simples de escrever usando a função <code>array()</code> do R,
prestando atenção apenas ao fato de que as coordenadas da array deveríam ir de
1 a 101 e não de -50 a 50.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler todos os passos como uma tabela</span>
</span></span><span class="line"><span class="cl"><span class="n">steps</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/22a_reactor_reboot.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;[ ,]|(\\.\\.)&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">transpose</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;state&#34;</span><span class="p">,</span> <span class="s">&#34;x1&#34;</span><span class="p">,</span> <span class="s">&#34;x2&#34;</span><span class="p">,</span> <span class="s">&#34;y1&#34;</span><span class="p">,</span> <span class="s">&#34;y2&#34;</span><span class="p">,</span> <span class="s">&#34;z1&#34;</span><span class="p">,</span> <span class="s">&#34;z2&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_chr</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">ends_with</span><span class="p">(</span><span class="s">&#34;1&#34;</span><span class="p">),</span> <span class="n">stringr</span><span class="o">::</span><span class="n">str_remove</span><span class="p">,</span> <span class="s">&#34;[a-z]=&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="o">-</span><span class="n">state</span><span class="p">),</span> <span class="n">as.integer</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">x2</span><span class="p">,</span> <span class="n">`:`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">y</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">`:`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="n">z1</span><span class="p">,</span> <span class="n">z2</span><span class="p">,</span> <span class="n">`:`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Criar reator como uma array 3D</span>
</span></span><span class="line"><span class="cl"><span class="n">reactor</span> <span class="o">&lt;-</span> <span class="nf">array</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="s">&#34;off&#34;</span><span class="p">,</span> <span class="m">303</span><span class="p">),</span> <span class="n">dim</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">101</span><span class="p">,</span> <span class="m">101</span><span class="p">,</span> <span class="m">101</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar nos passos</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">steps</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Coordenadas do cubóide</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">&lt;-</span> <span class="n">steps</span><span class="o">$</span><span class="n">x[[i]]</span> <span class="o">+</span> <span class="m">51</span>
</span></span><span class="line"><span class="cl">  <span class="n">y</span> <span class="o">&lt;-</span> <span class="n">steps</span><span class="o">$</span><span class="n">y[[i]]</span> <span class="o">+</span> <span class="m">51</span>
</span></span><span class="line"><span class="cl">  <span class="n">z</span> <span class="o">&lt;-</span> <span class="n">steps</span><span class="o">$</span><span class="n">z[[i]]</span> <span class="o">+</span> <span class="m">51</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Eliminar o que estiver fora do cubo -50:50</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">&lt;-</span> <span class="n">x[x</span> <span class="o">&gt;=</span> <span class="m">1</span> <span class="o">&amp;</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="m">101</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">y</span> <span class="o">&lt;-</span> <span class="n">y[y</span> <span class="o">&gt;=</span> <span class="m">1</span> <span class="o">&amp;</span> <span class="n">y</span> <span class="o">&lt;=</span> <span class="m">101</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">z</span> <span class="o">&lt;-</span> <span class="n">z[z</span> <span class="o">&gt;=</span> <span class="m">1</span> <span class="o">&amp;</span> <span class="n">z</span> <span class="o">&lt;=</span> <span class="m">101</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atribuir estado</span>
</span></span><span class="line"><span class="cl">  <span class="n">reactor[x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z]</span> <span class="o">&lt;-</span> <span class="n">steps</span><span class="o">$</span><span class="n">state[i]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contar cubos ligados</span>
</span></span><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="n">reactor</span> <span class="o">==</span> <span class="s">&#34;on&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 647076</span></span></span></code></pre></div><h2 id="reinicialização-do-reator-b">Reinicialização do Reator (B)</h2>
<p>Sem muita surpresa, o item 2 pedia para contarmos o número de cubos ligados ao
final do processo de reinicialização em <em>todo</em> o reator. Olhando o código acima,
parece que só seria necessário mudar as dimensões da array e tirar os filtros
dentro do loop, certo? Infelizmente não, pois com esse algoritmo ineficiente
precisaríamos contar aproximadamente 2 quadrilhões de cubos&hellip;</p>
<p>A solução foi, então, calcular apenas os limites das regiões e lidar com as suas
intersecções. Ou seja, se dois cubóides tiverem que ser ligados, então podemos
tomar nota das suas coordenadas e adicionar um novo cubóide de &ldquo;subtração&rdquo; na
nossa lista que servirá para remover uma cópia da intersecção que foi ligada
&ldquo;duas vezes&rdquo;. Resumidamente, estaremos contando apenas os volumes de cada
cubóide ligado e subtraíndo o volume de cada intersecção para não contar nada
duas vezes.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler todos os passos como uma tabela</span>
</span></span><span class="line"><span class="cl"><span class="n">steps</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/22b_reactor_reboot.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;[ ,]|(\\.\\.)&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">transpose</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">set_names</span><span class="p">(</span><span class="s">&#34;state&#34;</span><span class="p">,</span> <span class="s">&#34;x1&#34;</span><span class="p">,</span> <span class="s">&#34;x2&#34;</span><span class="p">,</span> <span class="s">&#34;y1&#34;</span><span class="p">,</span> <span class="s">&#34;y2&#34;</span><span class="p">,</span> <span class="s">&#34;z1&#34;</span><span class="p">,</span> <span class="s">&#34;z2&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">purrr</span><span class="o">::</span><span class="n">flatten_chr</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">tibble</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="nf">ends_with</span><span class="p">(</span><span class="s">&#34;1&#34;</span><span class="p">),</span> <span class="n">stringr</span><span class="o">::</span><span class="n">str_remove</span><span class="p">,</span> <span class="s">&#34;[a-z]=&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">across</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="o">-</span><span class="n">state</span><span class="p">),</span> <span class="n">as.integer</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">state</span> <span class="o">==</span> <span class="s">&#34;on&#34;</span><span class="p">,</span> <span class="m">1L</span><span class="p">,</span> <span class="m">-1L</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar nos passos Iterate over steps</span>
</span></span><span class="line"><span class="cl"><span class="n">cuboids</span> <span class="o">&lt;-</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">slice_head</span><span class="p">(</span><span class="n">steps</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">2</span><span class="o">:</span><span class="nf">nrow</span><span class="p">(</span><span class="n">steps</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos cubóides que já vimos</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">cuboids</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Calcular intersecção</span>
</span></span><span class="line"><span class="cl">    <span class="n">x1_inter</span> <span class="o">&lt;-</span> <span class="nf">max</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">x1[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">x1[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">x2_inter</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">x2[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">x2[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">y1_inter</span> <span class="o">&lt;-</span> <span class="nf">max</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">y1[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">y1[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">y2_inter</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">y2[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">y2[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">z1_inter</span> <span class="o">&lt;-</span> <span class="nf">max</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">z1[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">z1[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">z2_inter</span> <span class="o">&lt;-</span> <span class="nf">min</span><span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">z2[i]</span><span class="p">,</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">z2[j]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Adicionar intersecção à lista (com sinal virado)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">x1_inter</span> <span class="o">&lt;=</span> <span class="n">x2_inter</span> <span class="o">&amp;&amp;</span> <span class="n">y1_inter</span> <span class="o">&lt;=</span> <span class="n">y2_inter</span> <span class="o">&amp;&amp;</span> <span class="n">z1_inter</span> <span class="o">&lt;=</span> <span class="n">z2_inter</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">cuboids</span> <span class="o">&lt;-</span> <span class="n">tibble</span><span class="o">::</span><span class="nf">add_row</span><span class="p">(</span><span class="n">cuboids</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">state</span> <span class="o">=</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">state[j]</span> <span class="o">*</span> <span class="m">-1L</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">x1</span> <span class="o">=</span> <span class="n">x1_inter</span><span class="p">,</span> <span class="n">x2</span> <span class="o">=</span> <span class="n">x2_inter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">y1</span> <span class="o">=</span> <span class="n">y1_inter</span><span class="p">,</span> <span class="n">y2</span> <span class="o">=</span> <span class="n">y2_inter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">z1</span> <span class="o">=</span> <span class="n">z1_inter</span><span class="p">,</span> <span class="n">z2</span> <span class="o">=</span> <span class="n">z2_inter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar cubóide à lista se ele estiver ligado</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">steps</span><span class="o">$</span><span class="n">state[i]</span> <span class="o">==</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cuboids</span> <span class="o">&lt;-</span> <span class="n">tibble</span><span class="o">::</span><span class="nf">add_row</span><span class="p">(</span><span class="n">cuboids</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">state</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">state[i]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">x1</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">x1[i]</span><span class="p">,</span> <span class="n">x2</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">x2[i]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">y1</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">y1[i]</span><span class="p">,</span> <span class="n">y2</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">y2[i]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">z1</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">z1[i]</span><span class="p">,</span> <span class="n">z2</span> <span class="o">=</span> <span class="n">steps</span><span class="o">$</span><span class="n">z2[i]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Contar cubos ligados</span>
</span></span><span class="line"><span class="cl"><span class="n">on</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">cuboids</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Calcular volume</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">&lt;-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">x2[i]</span> <span class="o">-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">x1[i]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="n">y</span> <span class="o">&lt;-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">y2[i]</span> <span class="o">-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">y1[i]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">  <span class="n">z</span> <span class="o">&lt;-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">z2[i]</span> <span class="o">-</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">z1[i]</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Adicionar/remover à/da conta</span>
</span></span><span class="line"><span class="cl">  <span class="n">on</span> <span class="o">&lt;-</span> <span class="n">on</span> <span class="o">+</span> <span class="p">(</span><span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="o">*</span> <span class="n">z</span> <span class="o">*</span> <span class="n">cuboids</span><span class="o">$</span><span class="n">state[i]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="nf">format</span><span class="p">(</span><span class="n">on</span><span class="p">,</span> <span class="n">scientific</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1233304599156793</span></span></span></code></pre></div><h2 id="anfípodes-a-e-b">Anfípodes (A e B)</h2>
<p>O <a href="https://adventofcode.com/2021/day/23">dia 23</a> do AoC foi&hellip; Estranho. O
enunciado era fácil de entender, mas o código foi impossível de fazer. E não
estou exagerando: eu literamente não consegui fazer o código para resolver o
exercício. É verdade que eu fiquei doente hoje, então não sei se meus neurônios
estavam de cama.</p>
<p>No meu desespero, fui olhar o
<a href="https://www.reddit.com/r/adventofcode/comments/rmnozs/2021_day_23_solutions">subreddit do Advent</a>
em busca de sugestões de outros programadores e, quando cheguei lá, descobri que
várias pessoas estavam resolvendo o problema na mão! Uma boa alma tinha até
criado um
<a href="https://aochelper2021.blob.core.windows.net/day23/index.html"><em>helper</em> online</a>!</p>
<p>No final, a minha lição do dia de hoje é que nem sempre o jeito mais rápido de
resolver um problema é programando; às vezes é mais fácil usar a cabeça mesmo.
No caso, a cabeça da <a href="https://twitter.com/renata_mh">Renata Hirota</a>, que
resolveu o problema na mão em 10 minutos depois de eu ter passado o dia inteiro
na frente do computador tentando achar uma solução.</p>
<p>Sendo assim, deixo vocês com uma <a href="https://xkcd.com/974/">tirinha</a> do XKCD:</p>
<figure><img src="https://lente.dev/posts/aor-2021/the_general_problem.webp"/>
</figure>
<h2 id="unidade-lógica-e-aritmética-a-e-b">Unidade lógica e aritmética (A e B)</h2>
<p>O <a href="https://adventofcode.com/2021/day/24">penúltimo dia</a> do AoC de 2021 chegou e,
com ele, mais um problema que era mais fácil de resolver na mão! Hoje e ontem
vão ficar na história como exercícios de lógica e não de programação.</p>
<p>Sem mais delongas, deixo vocês com outra <a href="https://xkcd.com/1205/">tirinha</a> do
XKCD:</p>
<figure><img src="https://lente.dev/posts/aor-2021/is_it_worth_the_time_2x.webp"/>
</figure>
<h2 id="pepino-do-mar-a">Pepino-do-mar (A)</h2>
<p>Finalmente chegamos ao <a href="https://adventofcode.com/2021/day/25">último dia</a> do AoC
deste ano! O problema de hoje foi um verdadeiro presente de Natal: bem mais
simples que todos os dias anteriores. Nossa missão era acompanhar os movimentos
de dois grupos de pepinos-do-mar e encontrar o momento em que eles não poderiam
mais se mover.</p>
<p>Os pepinos estavam dispostos em uma matriz retangular e se moviam na direção
para a qual estavam apontando. Se o espaço em frente ao pepino estivesse vago
(<code>.</code>), então ele se movia.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Estado inicial:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...&gt;...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ......&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># v.....&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ......&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..vvv..</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Depis de 1 passo:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..vv&gt;..</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &gt;......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># v.....&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &gt;......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .......</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ....v..</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Depois de 58 passos (todos travados):</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..&gt;&gt;v&gt;vv..</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..v.&gt;&gt;vv..</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..&gt;&gt;v&gt;&gt;vv.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ..&gt;&gt;&gt;&gt;&gt;vv.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># v......&gt;vv</span>
</span></span><span class="line"><span class="cl"><span class="c1"># v&gt;v....&gt;&gt;v</span>
</span></span><span class="line"><span class="cl"><span class="c1"># vvv.....&gt;&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &gt;vv......&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .&gt;v.vv.v..</span></span></span></code></pre></div><p>Meu código ficou simples. Eu li o mapa do fundo do mar como uma matriz e
calculei todos os pepinos que podiam se mover; quando nenhum mais pudesse, eu
retornava o número de passos transcorridos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Ler fundo do mar como matriz</span>
</span></span><span class="line"><span class="cl"><span class="n">seafloor</span> <span class="o">&lt;-</span> <span class="s">&#34;data-raw/25a_sea_cucumber.txt&#34;</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">readr</span><span class="o">::</span><span class="nf">read_lines</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">flatten_chr</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">matrix</span><span class="p">(</span><span class="n">nrow</span> <span class="o">=</span> <span class="m">137</span><span class="p">,</span> <span class="n">ncol</span> <span class="o">=</span> <span class="m">139</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Iterar enquanto ainda há movimentos</span>
</span></span><span class="line"><span class="cl"><span class="n">i</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="kr">while</span> <span class="p">(</span><span class="kc">TRUE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">i</span> <span class="o">&lt;-</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Todos os pepinos</span>
</span></span><span class="line"><span class="cl">  <span class="n">e</span> <span class="o">&lt;-</span> <span class="nf">which</span><span class="p">(</span><span class="n">seafloor</span> <span class="o">==</span> <span class="s">&#34;&gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">s</span> <span class="o">&lt;-</span> <span class="nf">which</span><span class="p">(</span><span class="n">seafloor</span> <span class="o">==</span> <span class="s">&#34;v&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># As suas próximas posições</span>
</span></span><span class="line"><span class="cl">  <span class="n">next_e</span> <span class="o">&lt;-</span> <span class="p">((</span><span class="n">e</span> <span class="o">+</span> <span class="m">137</span><span class="p">)</span> <span class="o">%%</span> <span class="m">19043</span><span class="p">)</span> <span class="o">+</span> <span class="p">((</span><span class="n">e</span> <span class="o">+</span> <span class="m">137</span><span class="p">)</span> <span class="o">%%</span> <span class="m">19043</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="o">*</span> <span class="m">19043</span>
</span></span><span class="line"><span class="cl">  <span class="n">next_s</span> <span class="o">&lt;-</span> <span class="n">s</span> <span class="o">+</span> <span class="m">1</span> <span class="o">-</span> <span class="p">(</span><span class="n">s</span> <span class="o">%%</span> <span class="m">137</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span> <span class="o">*</span> <span class="m">137</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Mover todos os pepinos virados para a esquerda</span>
</span></span><span class="line"><span class="cl">  <span class="n">allowed_e</span> <span class="o">&lt;-</span> <span class="n">seafloor[next_e]</span> <span class="o">==</span> <span class="s">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">seafloor[next_e[allowed_e]]</span> <span class="o">&lt;-</span> <span class="n">seafloor[e[allowed_e]]</span>
</span></span><span class="line"><span class="cl">  <span class="n">seafloor[e[allowed_e]]</span> <span class="o">&lt;-</span> <span class="s">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Mover todos os pepinos virados para baixo</span>
</span></span><span class="line"><span class="cl">  <span class="n">allowed_s</span> <span class="o">&lt;-</span> <span class="n">seafloor[next_s]</span> <span class="o">==</span> <span class="s">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">seafloor[next_s[allowed_s]]</span> <span class="o">&lt;-</span> <span class="n">seafloor[s[allowed_s]]</span>
</span></span><span class="line"><span class="cl">  <span class="n">seafloor[s[allowed_s]]</span> <span class="o">&lt;-</span> <span class="s">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Verificar condição de parada</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">all</span><span class="p">(</span><span class="o">!</span><span class="n">allowed_e</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nf">all</span><span class="p">(</span><span class="o">!</span><span class="n">allowed_s</span><span class="p">))</span> <span class="kr">break</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imprimir</span>
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 518</span></span></span></code></pre></div><h2 id="pepino-do-mar-b">Pepino-do-mar (B)</h2>
<p>O segundo item me pegou de surpresa porque&hellip; Não havia segundo item! A
historinha que estava sendo contada ao longo do AoC foi finalmente concluída e
ganhamos a última estrela de graça.</p>
<p>E esse foi o fim da aventura. Muito obrigado por me acompanhar nesses últimos 25
dias de programação intensa! Espero que tenham gostado e, até que enfim, boas
festas!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Tutorial de dots</title>
      <link>https://lente.dev/posts/tutorial-dots/</link>
      <pubDate>Sat, 04 Dec 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/tutorial-dots/</guid>
      <description>Aprenda de uma vez por todas como funcionam os &amp;lsquo;&amp;hellip;&amp;rsquo;</description>
      <content:encoded><![CDATA[<p>Chamdos de &ldquo;três pontinhos&rdquo;, &ldquo;reticências&rdquo;, &ldquo;dots&rdquo; ou &ldquo;ellipsis&rdquo;, os
<code>...</code> são uma das funcionalidades mais comuns do R, mas ao mesmo tempo
uma das menos conhecidas. Explicá-los em linguagem técnica é muito
simples: eles são os <a href="https://en.wikipedia.org/wiki/Variadic_function">argumentos
variádicos</a> do R! O
difícil é entender de verdade o que eles são e como usá-los. Vamos
abandonar o jargão e sigamos em frente, agora em bom português…</p>
<p>Obs.: O nome correto no R para os <code>...</code> é dots, então vou usar esse
termo a partir de agora. A prova disso é que, para consultar a sua
documentação, executamos <code>?dots</code>.</p>
<h2 id="onde-estão">Onde estão</h2>
<p>Como eu disse anteriormente, eles são bastante comuns, mas quão comuns
exatamente? Talvez mais do que você imagine. Veja abaixo os
<a href="https://en.wikipedia.org/wiki/Function_prototype">protótipos</a> de
algumas poucas funções que talvez você conheça (ignore o <code>NULL</code>, ele é
parte da saída da função <code>args()</code>):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">args</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; function (..., na.rm = FALSE)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; NULL</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">args</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; function (...)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; NULL</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">args</span><span class="p">(</span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; function (.data, ...)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; NULL</span></span></span></code></pre></div><p>Te convenci? Entender os dots é, portanto, uma excelente arma no arsenal
do programador de R, tanto que eles são usados pelas funções mais
importantes da linguagem toda.</p>
<h2 id="o-que-são">O que são</h2>
<p>De forma bem geral, os dots são um argumento que, quando colocado na sua
função, pode ser substituído por qualquer coisa pelo usuário. Na função
<code>sum()</code>, por exemplo, os dots podem virar uma série de números (quantos
o usuário quiser).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 15</span></span></span></code></pre></div><p>Quando falamos de argumentos normais, não precisamos declarar seus
argumentos caso estejamos utilizando-os na ordem correta. Os dots,
entretanto, podem ser substituídos por qualquer número de objetos, então
eles quebram essa regra; qualquer argumento que vier <em>depois</em> dos dots
precisa ser nomeado.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Não funciona do jeito esperado (TRUE mais um elemento dos dots)</span>
</span></span><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="kc">NA</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] NA</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Agora sim</span>
</span></span><span class="line"><span class="cl"><span class="nf">sum</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="kc">NA</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 12</span></span></span></code></pre></div><p>Sem os dots a função <code>sum()</code> estaria limitada a receber um vetor de
números, mas com essa ferramenta ela passa a poder receber números
separados como se fossem cada um um argumento. A função <code>c()</code>,
entretanto, não poderia ser implementada sem os dots.</p>
<p>O seu poder completo, porém, fica mais claro na função
<code>dplyr::select()</code>. Aqui vemos que podemos até dar nomes arbitrários para
os &ldquo;argumentos&rdquo; de dentro dos dots e a função pode usá-los sem o menor
problema:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">mtcars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span> <span class="n">cil</span> <span class="o">=</span> <span class="n">cyl</span><span class="p">,</span> <span class="n">marcha</span> <span class="o">=</span> <span class="n">gear</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">head</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;                    mpg cil marcha</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Mazda RX4         21.0   6      4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Mazda RX4 Wag     21.0   6      4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Datsun 710        22.8   4      4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Hornet 4 Drive    21.4   6      3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Hornet Sportabout 18.7   8      3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Valiant           18.1   6      3</span></span></span></code></pre></div><p>Perceba que a função <code>dplyr::select()</code> não tem como saber quantas
colunas nós vamos selecionar e quais nomes eu vou dar para cada uma,
tornando impossível o uso de argumentos convencionais. O uso do dots é
inevitável nesses casos.</p>
<h2 id="como-usá-los">Como usá-los</h2>
<p>Agora que já vimos universalidade e importância dos dots, chegou a hora
de entender como eles funcionam e como usá-los. Vamos começar com um
exemplo simples: criar uma função que captura quaisquer argumentos que o
usuário resolver passar e imprime seus valores.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Captura dots e os imprime como uma lista</span>
</span></span><span class="line"><span class="cl"><span class="n">captura</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">list</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">captura</span><span class="p">(</span><span class="n">arg1</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">arg2</span> <span class="o">=</span> <span class="s">&#34;b&#34;</span><span class="p">,</span> <span class="n">arg3</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; $arg1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; $arg2</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;b&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; $arg3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] FALSE</span></span></span></code></pre></div><p>Simples, né? 90% das vezes podemos simplesmente transformar os dots em
uma lista comum com <code>list(...)</code> e utilizá-la normalmente. Em breve
ficará mais claro por que isso funciona.</p>
<p>Se quisermos capturar argumentos específicos dentro dos dots, aí podemos
usar uma função especial chamada <code>...elt()</code> (sim, as reticências fazem
parte de seu nome):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Captura dots e os imprime como uma lista</span>
</span></span><span class="line"><span class="cl"><span class="n">captura_segundo</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">...elt</span><span class="p">(</span><span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">captura_segundo</span><span class="p">(</span><span class="n">arg1</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">arg2</span> <span class="o">=</span> <span class="s">&#34;b&#34;</span><span class="p">,</span> <span class="n">arg3</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;b&#34;</span></span></span></code></pre></div><p>A terceira forma de usar os dots é os transportando para uma função que
recebe dots. Como já deve ter ficado evidente, os dots podem ser
substituídos por qualquer número de argumentos por parte do usuário, mas
eles também podem ser passados como argumento no lugar dos dots de outra
função!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">filtra_seleciona</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">marchas</span><span class="p">,</span> <span class="kc">...</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">mtcars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">gear</span> <span class="o">==</span> <span class="n">marchas</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">head</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">filtra_seleciona</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="n">mpg</span><span class="p">,</span> <span class="n">cil</span> <span class="o">=</span> <span class="n">cyl</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;                mpg cil</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Mazda RX4     21.0   6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Mazda RX4 Wag 21.0   6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Datsun 710    22.8   4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Merc 240D     24.4   4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Merc 230      22.8   4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Merc 280      19.2   6</span></span></span></code></pre></div><p>No caso acima, os dots eram <code>mpg, cil = cyl</code> e isso foi transportado
perfeitamente para dentro de <code>dplyr::select()</code>.</p>
<p>Para fechar este tutorial com chave de ouro, vamos criar uma função
arbitrária que precisa de um argumento depois dos dots: nossa função
deve receber qualquer quantidade de valores numéricos, ignorar o
primeiro e somar o resto com <code>n</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ignora_um_soma_n</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="kc">...</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">valores</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">valores</span> <span class="o">&lt;-</span> <span class="n">valores[</span><span class="m">-1</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="nf">unlist</span><span class="p">(</span><span class="n">valores</span><span class="p">)</span> <span class="o">+</span> <span class="n">n</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ignora_um_soma_n</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="m">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 12 13 14 15</span></span></span></code></pre></div><p>Espero que agora esteja pelo menos um pouco mais claro o funcionamento
dos dots! Se não, pode entrar em contato comigo via
<a href="https://twitter.com/ctlente">Twitter</a> ou postar uma dúvida no nosso
<a href="https://discourse.curso-r.com/">fórum</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>R no VS Code</title>
      <link>https://lente.dev/posts/vscode-r/</link>
      <pubDate>Sat, 06 Nov 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/vscode-r/</guid>
      <description>Como programar R no editor de código mais popular da atualidade</description>
      <content:encoded><![CDATA[<p>O RStudio é uma IDE (<em>Integrated development environment</em>) incrível. Em sua
<a href="https://www.rstudio.com/products/rstudio/release-notes/">versão mais recente</a>
a ferramenta tem suporte para visualizações interativas, traz controle de versão
embutido, consegue executar <em>jobs</em> em paralelo e permite programar não só em R,
mas também em Python!</p>
<p>Ele não é, contudo, perfeito. Pessoalmente eu tenho algumas críticas a algumas
de suas idiossincrasias, principalmente no tocante à camada interpretativa que
embrulha o R&hellip; Depois de muitos anos programando R e usando somente o RStudio,
a lista de coisas que começaram a me incomodar foi crescendo:</p>
<ul>
<li>
<p>Às vezes, imprimir um objeto de texto muito grande trava a interface. Cancelar
essa operação depois que ela foi iniciada também nem sempre funciona.</p>
</li>
<li>
<p>O navegador de arquivos, com suas caixinhas clicáveis, deixa muito a desejar.
Não deveria ser tão chato copiar e deletar arquivos.</p>
</li>
</ul>
<figure><img src="https://lente.dev/posts/vscode-r/multiple-items-selected.webp"/>
</figure>
<ul>
<li>
<p>Até hoje não existe um jeito de substituir um termo (<em>find-replace</em>) em
múltiplos arquivos. É possível procurar um termo na pasta toda
(<strong>Ctrl + Shift + F</strong>), mas nada de substituí-lo.</p>
</li>
<li>
<p>Até onde eu sei, é impossível abrir uma pasta com o RStudio sem que seja
criado um arquivo <code>.Rproj</code>. Por que é necessário criar um arquivo para abrir uma
mera pasta?</p>
</li>
<li>
<p>Por padrão, as
<a href="https://github.com/rstudio/rstudio/issues/9692">mensagens de diagnóstico</a>
continuam sujando as sessões locais. Novos usuários podem estranhar esse tipo
de alerta inesperado.</p>
</li>
</ul>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#&gt; Registered S3 method overwritten by &#39;quantmod&#39;:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   method            from</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   as.zoo.data.frame zoo</span></span></span></code></pre></div><ul>
<li>
<p>Honestamente, a interface está visualmente cada vez mais atrasada. Ícones
coloridos e difíceis de diferenciar somados a um sistema de design limitado é
mais que um incômodo em 2021.</p>
</li>
<li>
<p>Ainda é impossível executar funções do <code>furrr</code> no modo <em>multicore</em> dentro do
console do RStudio.</p>
</li>
</ul>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">plan</span><span class="p">(</span><span class="s">&#34;multicore&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning message:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; In supportsMulticoreAndRStudio(...) :</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   [ONE-TIME WARNING] Forked processing (&#39;multicore&#39;) is not supported when</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; running R from RStudio because it is considered unstable. For more details,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; how to control forked processing or not, and how to silence this warning in</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; future R sessions, see ?parallelly::supportsMulticore</span></span></span></code></pre></div><ul>
<li>
<p>A interrupção da execução continua tendo problemas com tarefas em C e
paralelas. Quem nunca segurou <strong>Esc</strong> na esperança de interromper um comando
só para ter que esperar ele terminar de rodar de qualquer jeito?</p>
</li>
<li>
<p>A bombinha. Por que a IDE inteira cai se o problema está no código executado?</p>
</li>
</ul>
<figure><img src="https://lente.dev/posts/vscode-r/bomba.webp"/>
</figure>
<h2 id="uma-possível-alternativa">Uma Possível Alternativa</h2>
<p>Apesar de nenhum desses problemas ser fatal, eu ainda acho interessante procurar
uma alternativa. Depender de apenas um software para programar também acaba
virando um problema caso ele deixe de ser mantido; note que, no momento em que
escrevo, aproximadamente 20% das
<a href="https://github.com/rstudio/rstudio/issues"><em>issues</em></a> já cadastradas no GitHub
do RStudio ainda estão abertas.</p>
<p>É assim que chegamos às alternativas. Eu já testei o
<a href="https://github.com/jalvesaq/Nvim-R">Nvim-R</a> (extensão para Vim programada por
um brasileiro!) e o <a href="https://ess.r-project.org/">ESS</a> (extensão para o Emacs),
mas a curva de aprendizado das duas ferramentas acabou se tornando um obstáculo.
No final eu cheguei ao
<a href="https://marketplace.visualstudio.com/items?itemName=Ikuyadeu.r">vscode-R</a>, a
extensão de R para o VS Code.</p>
<figure><img src="https://lente.dev/posts/vscode-r/vscode.webp"/>
</figure>
<p>Para quem não sabe, o VS Code é atualmente o editor de código mais popular do
mundo. De acordo com uma
<a href="https://insights.stackoverflow.com/survey/2021#most-popular-technologies-new-collab-tools">pesquisa</a>
feita pelo Stack Overflow em 2021, 71% dos programadores usam o VS Code para
programar, então ele deve ter algo de bom.</p>
<p>Na minha opinião, os benefícios do VS Code, em geral, giram em torno da
flexibilidade da ferramenta. É muito fácil instalar plugins, modificar o seu
visual e customizar o seu funcionamento, permitindo que a IDE se torne
verdadeiramente sua. Já, no tocante ao R, o maior benefício é que a sua
integração com a linguagem se dá através de um terminal, ou seja, não é
embrulhada como no RStudio.</p>
<h2 id="guia-de-instalação">Guia de Instalação</h2>
<p>Instalar o VS Code em si é fácil. Basta ir no
<a href="https://code.visualstudio.com/">site</a> e baixar a versão para o seu sistema
operacional. Depois de abrir o programa, você verá uma lista de extensões
sugeridas e é aí que precisamos configurar o R.</p>
<p>A extensão que procuramos é identificada pelo código <code>ikuyadeu.r</code>. Basta
instalá-la e seguir as instruções para o seu sistema operacional:
<a href="https://github.com/REditorSupport/vscode-R/wiki/Installation:-Windows">Windows</a>,
<a href="https://github.com/REditorSupport/vscode-R/wiki/Installation:-macOS">MacOS</a> ou
<a href="https://github.com/REditorSupport/vscode-R/wiki/Installation:-Linux">Linux</a>.</p>
<p>Assumindo que você esteja no Windows, os próximos passos são os seguintes:</p>
<ol>
<li>Instalar, no R, o pacote <code>languageserver</code>:</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;languageserver&#34;</span><span class="p">)</span></span></span></code></pre></div><ol start="2">
<li>Instalar a <a href="https://www.python.org/downloads/">versão mais recente</a> do
Python. Se você tiver qualquer versão a partir da 3, já é o suficiente:</li>
</ol>
<figure><img src="https://lente.dev/posts/vscode-r/python.webp"/>
</figure>
<ol start="3">
<li>Instalar o <a href="https://github.com/randy3k/radian">Radian</a>, um console moderno
para o R, e descobir onde ele foi instalado. Executar o seguinte no <em>prompt</em> de
comando!</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pip install -U radian
</span></span><span class="line"><span class="cl">where.exe radian</span></span></code></pre></div><ol start="4">
<li>Abrir o arquivo de configurações avançadas do VS Code: aperte
<strong>Ctrl + Shift + P</strong>, digite &ldquo;open settings&rdquo; e clique em &ldquo;Open Settings (JSON)&rdquo;.
Colar o texto a seguir no arquivo e salvar (substitua o caminho do <code>rterm</code>
pela localização do Radian):</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;r.bracketedPaste&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;r.rterm.windows&#34;</span><span class="p">:</span> <span class="s2">&#34;C:\\Users\\user\\...\\radian.exe&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><ol start="5">
<li>Caso você use o debugger, instalar a extensão
<a href="https://marketplace.visualstudio.com/items?itemName=RDebugger.r-debugger">R Debugger</a>
e o pacote <code>vscDebugger</code>:</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">remotes</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;ManuelHentschel/vscDebugger&#34;</span><span class="p">)</span></span></span></code></pre></div><ol start="6">
<li>Habilitar a renderização de visualizações com o pacote <code>httpgd</code>:</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;httpgd&#34;</span><span class="p">)</span></span></span></code></pre></div><ol start="7">
<li>Finalmente, indicar o uso do <code>httpgd</code> para o VS Code:</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">usethis</span><span class="o">::</span><span class="nf">edit_r_profile</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Colar a linha abaixo no .Rprofile</span>
</span></span><span class="line"><span class="cl"><span class="nf">options</span><span class="p">(</span><span class="n">vsc.use_httpgd</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span></span></span></code></pre></div><h2 id="usando-o-vs-code">Usando o VS Code</h2>
<p>Se você tiver configurado tudo corretamente, o VS Code estará pronto para uso.
Para programar em R, basta abrir a pasta de um projeto e começar! Assim que você
executar o primeiro comando R com <strong>Ctrl + Enter</strong>, um console R irá aparecer e
você pode seguir a vida normalmente.</p>
<figure><img src="https://lente.dev/posts/vscode-r/demo.webp"/>
</figure>
<p>Minha principal sugestão para o seu futuro no VS Code é: explore! Se algo te
incomoda, a change de isso ser modificável é de praticamente 100%. Veja vídeos
no YouTube de outras pessoas trabalhando com R no VS Code e procure extensões
legais na loja. Se algo parecer que está errado, se informe.</p>
<p>A minha primeira semana com o VS Code foi de adaptação, configurando tudo do
jeito que eu mais gosto. A partir daí, eu nunca mais precisei mexer em nada,
então consigo atestar de que a plataforma é robusta.</p>
<h2 id="bônus-configuração-extra">Bônus: Configuração Extra</h2>
<p>Para que você não precise ter o mesmo trabalho que eu, aqui estão as minhas
principais configurações do VS Code. Veja se elas funcionam para o seu estilo
de trabalho. Note apenas que a minha configuração é do Mac! Troque a tecla <code>cmd</code>
por <code>ctrl</code> de acordo.</p>
<p><code>settings.json</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;r.rterm.mac&#34;</span><span class="p">:</span> <span class="s2">&#34;/opt/homebrew/bin/radian&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;r.bracketedPaste&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;editor.minimap.enabled&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;workbench.startupEditor&#34;</span><span class="p">:</span> <span class="s2">&#34;none&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;redhat.telemetry.enabled&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;editor.tabSize&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;security.workspace.trust.untrustedFiles&#34;</span><span class="p">:</span> <span class="s2">&#34;open&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;explorer.confirmDelete&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;files.defaultLanguage&#34;</span><span class="p">:</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;terminal.integrated.defaultLocation&#34;</span><span class="p">:</span> <span class="s2">&#34;editor&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;diffEditor.ignoreTrimWhitespace&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;files.trimTrailingWhitespace&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;editor.rulers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="mi">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="mi">120</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p><code>keybindings.json</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// Place your key bindings in this file to override the defaults
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// RStudio key bindings
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;cmd+shift+m&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;type&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34; %&gt;%&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;editorTextFocus &amp;&amp; editorLangId == &#39;r&#39;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;type&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34; &lt;- &#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;editorTextFocus &amp;&amp; editorLangId == &#39;r&#39;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;r.loadAll&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Custom shortcuts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+alt+cmd+left&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.action.moveEditorToPreviousGroup&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+alt+cmd+right&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.action.moveEditorToNextGroup&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.view.scm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.scm.active&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.view.scm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.scm.active &amp;&amp; !gitlens:disabled &amp;&amp; config.gitlens.keymap == &#39;chorded&#39;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Conflicts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+cmd+left&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.focusPreviousPane&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+cmd+right&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.focusNextPane&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+m&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.actions.view.problems&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.panel.markers.view.active&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+alt+cmd+left&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-cursorColumnSelectLeft&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;textInputFocus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+cmd+left&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.moveEditorToPreviousGroup&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+cmd+right&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.moveEditorToNextGroup&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+alt+cmd+right&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-cursorColumnSelectRight&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;textInputFocus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-editor.action.previousMatchFindAction&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;editorFocus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.findPrevious&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFindFocused &amp;&amp; terminalProcessSupported || terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-editor.action.nextMatchFindAction&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;editorFocus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;cmd+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.findNext&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFindFocused &amp;&amp; terminalProcessSupported || terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+shift+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.view.scm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.scm.active&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+shift+g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.view.scm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;workbench.scm.active &amp;&amp; !gitlens:disabled &amp;&amp; config.gitlens.keymap == &#39;chorded&#39;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-selectAllSearchEditorMatches&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;inSearchEditor&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-editor.action.selectHighlights&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;editorFocus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;shift+cmd+l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-addCursorsAtSearchResults&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;fileMatchOrMatchFocus &amp;&amp; searchViewletVisible&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+cmd+right&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.focusNextPane&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFocus &amp;&amp; terminalHasBeenCreated || terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;key&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+cmd+left&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;-workbench.action.terminal.focusPreviousPane&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;when&#34;</span><span class="p">:</span> <span class="s2">&#34;terminalFocus &amp;&amp; terminalHasBeenCreated || terminalFocus &amp;&amp; terminalProcessSupported&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Entendendo o lambda do R</title>
      <link>https://lente.dev/posts/lambda/</link>
      <pubDate>Mon, 16 Aug 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/lambda/</guid>
      <description>Entendenda finalmente as funções lamda do R</description>
      <content:encoded><![CDATA[<p>Uma das funcionalidades mais interessantes do R é a possibilidade de
estender a linguagem para domínios específicos. A <a href="https://blog.curso-r.com/posts/2021-07-27-rlang-para-filhotes/"><em>non-standard
evaluation</em></a>
garante que até modificações à estrutura fundamental do R podem ser
realizadas sem problema. Hoje vamos falar de um assunto que muita gente
quer aprender, mas que pouca gente entende de verdade: funções anônimas.</p>
<p>Se você não souber o que é uma função anônima, pode ser que você conheça
esse conceito por outro nome. Também chamada de “função lambda”,
“notação de fórmula” ou “notação de til”, ela aparece principalmente em
programas que usam o {purrr} apesar de não serem exclusividade desse
pacote. Resumindo, se você já viu algo do tipo <code>~.x</code> e não entendeu do
que se tratava, este post é para você.</p>
<h2 id="introdução">Introdução</h2>
<p>Funções anônimas são, essencialmente, um jeito de simplificar a criação
de funções pequenas. Em poucas palavras, o nosso objetivo é não ter que
declarar uma função nova inteira com <code>function() { ... }</code> para poder
usá-la dentro de um programa.</p>
<p>O exemplo que será utilizado na explicação a seguir será a função
<code>conta_na()</code> que (não surpreendentemente) conta o número de <code>NA</code>s em um
vetor. Vamos usá-la dentro de um <code>map()</code> para que ela seja aplicada a
todas as colunas de um data frame. Sendo assim, partiremos da forma mais
verborrágica possível desse código e tentaremos chegar, intuitivamente,
nas funções anônimas.</p>
<p>Uma ressalva importante é que a notação explicada aqui <strong>só funciona
dentro do {tidyverse}</strong>! No final do texto será apresentada uma
alternativa que funciona fora desse contexto, mas, por enquanto, a
notação abaixo só pode aparecer nos argumentos <code>.f</code>, <code>.fn</code> e <code>.fns</code>
utilizados dentro do {tidyverse}.</p>
<h2 id="conceito">Conceito</h2>
<p>Vamos imaginar uma função <code>conta_na()</code> que conta o número de <code>NA</code>s em
uma coluna de um data frame. Para aplicá-la a todas as colunas do data
frame, podemos, por exemplo, utilizar a função <code>map()</code> do pacote {purrr}
como no exemplo abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">conta_na</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       name     height       mass hair_color skin_color  eye_color birth_year</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          0          6         28          5          0          0         44</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;        sex     gender  homeworld    species      films   vehicles  starships</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          4          4         10          4          0          0          0</span></span></span></code></pre></div><p>No R, quando temos uma função simples de uma linha, é perfeitamente
possível não colocar o seu corpo em uma linha separada. Veja como o
código já fica um pouco mais compacto (saída omitida daqui em diante):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="p">{</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">conta_na</span><span class="p">)</span></span></span></code></pre></div><p>Agora, se temos uma função que cabe inteira em uma linha, o R nos
permite também omitir as chaves: por exemplo, m if-else pode ser escrito
<code>if (cond) resp1 else resp2</code> se as respostas não tiverem mais de uma
linha. No nosso caso, vamos reduzir ainda mais a <code>conta_na()</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">conta_na</span><span class="p">)</span></span></span></code></pre></div><p>O próximo passo seria encurtar o nome do argumento da função, utilizando
algo mais genérico. Poucas pessoas sabem, mas o R permite nomes
começando com <code>.</code>! Por motivos que ficarão claros a seguir, vamos
escolher <code>.x</code> para ser o nome do nosso argumento:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">.x</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">conta_na</span><span class="p">)</span></span></span></code></pre></div><p>Agora vem a grande sacada. Tudo que fizemos até agora funciona no R como
um todo, mas, se atendermos algumas condições extras, podemos reduzir
ainda mais essa função.</p>
<p>Vamos lá: se a função i) tiver apenas uma linha, ii) tiver apenas 1
argumento, iii) tiver <code>.x</code> como seu único argumento <code>.x</code> e iv) estiver
sendo utilizada como argumento de uma função do {tidyverse}, então
podemos omitir o <code>function(.x)</code> (já que isso é informação redundante
dadas as condições) e trocá-lo por um singelo <code>~</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="o">~</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">conta_na</span><span class="p">)</span></span></span></code></pre></div><p>O último passo é o motivo de chamarmos essa notação de “função anônima”.
Dado que nossa função já é tão pequena e utilizamos ela em apenas um
lugar, por que precisamos dar um nome para ela? É mais fácil declará-la
diretamente dentro do <code>map()</code> sem um nome, ou seja, “anonimamente”:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="o">~</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">.x</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       name     height       mass hair_color skin_color  eye_color birth_year</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          0          6         28          5          0          0         44</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;        sex     gender  homeworld    species      films   vehicles  starships</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          4          4         10          4          0          0          0</span></span></span></code></pre></div><p>Pronto, agora você sabe o que significa uma função do tipo <code>~.x</code>. Para
treinar, tente fazer o processo reverso como no caso abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Fração de valores distintos dentre todos</span>
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="o">~</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Desanonimizar</span>
</span></span><span class="line"><span class="cl"><span class="n">frac_distintos</span> <span class="o">&lt;-</span> <span class="o">~</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">.x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="n">frac_distintos</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Remover a notação de til (não é mais necessário mexer no map())</span>
</span></span><span class="line"><span class="cl"><span class="n">frac_distintos</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">.x</span><span class="p">)</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">.x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Utilizar um nome melhor para o argumento</span>
</span></span><span class="line"><span class="cl"><span class="n">frac_distintos</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">vec</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Recolocar as chaves</span>
</span></span><span class="line"><span class="cl"><span class="n">frac_distintos</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">{</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">vec</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Identar o corpo da função</span>
</span></span><span class="line"><span class="cl"><span class="n">frac_distintos</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">vec</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Agora fica bem mais fácil de entender o que faz o <code>map()</code> lá do começo.</p>
<h2 id="futuro">Futuro</h2>
<p>A pergunta óbvia agora é: existe um jeito de fazer algo assim fora do
{tidyverse}? A resposta é sim e não.</p>
<p>Desde o <a href="https://lente.dev/posts/novo-pipe/">R 4.1</a>,
o R introduziu a sua própria notação anônima. Ela funciona de maneira
muito similar ao <code>~</code>, com a diferença de que você precisa dizer o nome
do seu argumento. Abaixo deixo vocês com o processo de simplificação da
função <code>conta_na()</code> para a sua versão anônima que pode ser utilizada em
qualquer lugar e não só no {tidyverse}:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Conta o número de NAs em um vetor</span>
</span></span><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Usar uma linha só</span>
</span></span><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="p">{</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Sem necessidade de usar chaves</span>
</span></span><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Se a função tem uma linha, podemos usar a nova notação</span>
</span></span><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="nf">\</span><span class="p">(</span><span class="n">vetor</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vetor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># O nome do argumento pode ser qualquer coisa, não importa</span>
</span></span><span class="line"><span class="cl"><span class="n">conta_na</span> <span class="o">&lt;-</span> <span class="nf">\</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Anonimizar</span>
</span></span><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">starwars</span><span class="p">,</span> <span class="nf">\</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">v</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       name     height       mass hair_color skin_color  eye_color birth_year</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          0          6         28          5          0          0         44</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;        sex     gender  homeworld    species      films   vehicles  starships</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;          4          4         10          4          0          0          0</span></span></span></code></pre></div><p>Quase tão bom quanto a notação de til!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rolando dados com droll</title>
      <link>https://lente.dev/posts/droll/</link>
      <pubDate>Thu, 12 Aug 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/droll/</guid>
      <description>Um pacote para analisar rolagens de dados e calcular suas probabilidades</description>
      <content:encoded><![CDATA[<p><strong>droll</strong> [ˈdrōl] <em>(adj.)</em>. <strong>1</strong>. (Ing.) Divertido, especialmente de
forma incomum.</p>
<p>droll é um pacote R para parsear a notação usada para descrever dados,
analisar rolagens, calcular probabilidades de sucesso e gerar gráficos
das distribuições dos resultados. Ele pode ajudar DMs detalhistas a
preparar encontros (in)justos com antecedência ou decidir a DC
apropriada para um teste na hora. Jogadores também podem usar o droll
para determinar a melhor estratégia quando em uma situação difícil.</p>
<p>Ele foi feito para ser uma alternativa muito leve (só uma dependência
obrigatória), muito rápida (menos de 0,4s para calcular a distribuição
completa de 40d6) e muito precisa (representação interna simbólica
cortesia do Ryacas) para o <a href="https://anydice.com/">anydice</a> no R.</p>
<h2 id="instalação">Instalação</h2>
<p>Instale a versão estável do CRAN com:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;droll&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Ou instale a versão em desenvolvimento do
<a href="https://github.com/curso-r/droll">GitHub</a> com:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># install.packages(&#34;remotes&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">remotes</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;curso-r/droll&#34;</span><span class="p">)</span></span></span></code></pre></div><h2 id="uso">Uso</h2>
<p>O que você procura no droll? Você é um usuário nível 1, um programador
experiente nível 10, ou um estatístico divino nível 20? Escolha sua
classe:</p>
<h3 id="-usuário">🖍️ Usuário</h3>
<p>O uso mais básico do droll envolve simplesmente rolar dados. Você pode
criar qualquer dado que quiser com a função <code>d()</code> e escrever qualquer
expressão que envolva aquele dado. Note que, se você quiser rolar NdX,
você deveria escrever <code>N * dX</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar alguns dados</span>
</span></span><span class="line"><span class="cl"><span class="n">d20</span> <span class="o">&lt;-</span> <span class="nf">d</span><span class="p">(</span><span class="m">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d6</span>  <span class="o">&lt;-</span> <span class="nf">d</span><span class="p">(</span><span class="m">6</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d4</span>  <span class="o">&lt;-</span> <span class="nf">d</span><span class="p">(</span><span class="m">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rolar um teste enquanto abençoado</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">)</span> <span class="o">+</span> <span class="n">d4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 22</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rolar o dano!!</span>
</span></span><span class="line"><span class="cl"><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 22</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rolar um teste de resistência de destreza com desvantagem</span>
</span></span><span class="line"><span class="cl"><span class="kr">if</span> <span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">d20</span><span class="p">,</span> <span class="n">d20</span><span class="p">)</span> <span class="o">+</span> <span class="m">4</span> <span class="o">&lt;</span> <span class="m">18</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">print</span><span class="p">(</span><span class="s">&#34;Dano completo!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">print</span><span class="p">(</span><span class="s">&#34;Metade do dano.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Dano completo!&#34;</span></span></span></code></pre></div><p>Simples e fácil, certo? Se você é um DM, você também pode querer usar
duas funções: <code>check_prob()</code> e <code>check_dc()</code>. Elas permitem que você,
respectivamente, calcule a probabilidade de passar (ou falhar) em um
teste e encontrar a DC necessária para que um teste tenha uma certa
probabilidade de sucesso (ou erro). Você não precisa nem criar os dados
que você vai usar dentro delas!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Qual é a probabilidade que esse jogador passe em um teste de DC 15?</span>
</span></span><span class="line"><span class="cl"><span class="nf">check_prob</span><span class="p">(</span><span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">,</span> <span class="m">15</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 0.7</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Qual deveria ser a DC para que esse jogador tenha 50% de chance de sucesso?</span>
</span></span><span class="line"><span class="cl"><span class="nf">check_dc</span><span class="p">(</span><span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">,</span> <span class="m">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 19</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Qual é a probabilidade desse jogador falhar em um teste de DC 10?</span>
</span></span><span class="line"><span class="cl"><span class="nf">check_prob</span><span class="p">(</span><span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">,</span> <span class="m">10</span><span class="p">,</span> <span class="n">success</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 0.05</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Qual deveria ser a DC para que esse jogador tenha 90% de chance de falha?</span>
</span></span><span class="line"><span class="cl"><span class="nf">check_dc</span><span class="p">(</span><span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">,</span> <span class="m">0.9</span><span class="p">,</span> <span class="n">success</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 27</span></span></span></code></pre></div><p>Não há funções do tipo <code>attack_*()</code> porque as mecânicas de ataques e
testes são as mesmas, ou seja, sucesso equivale a rolar um valor maior
ou igual a um certo patamar. Essas funções podem, portanto, ser usadas
para ataques também!</p>
<h3 id="-programador">🗡️ Programador</h3>
<p>Se você já está acostumado com a notação d/p/q/r do R, pode ser que você
queira mais detalhes sobre a distribuição de uma rolagem. É para isso
que as funções <code>droll()</code>, <code>proll()</code>, <code>qroll()</code>, e <code>rroll()</code> existem!
Elas são, respectivamente, a densidade, a função de distribuição, a
função de quantil, e a geração aleatória da distribuição definida por
uma expressão de rolagem.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># P[d20 + 8 = 12]</span>
</span></span><span class="line"><span class="cl"><span class="nf">droll</span><span class="p">(</span><span class="m">12</span><span class="p">,</span> <span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 0.05</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># P[d20 + 8 &lt;= 12]</span>
</span></span><span class="line"><span class="cl"><span class="nf">proll</span><span class="p">(</span><span class="m">12</span><span class="p">,</span> <span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 0.2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># inf{x: P[d20 + 8 &lt;= x] &gt;= 0.5}</span>
</span></span><span class="line"><span class="cl"><span class="nf">qroll</span><span class="p">(</span><span class="m">0.5</span><span class="p">,</span> <span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 18</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Amostrar 3 vezes de d20 + 8</span>
</span></span><span class="line"><span class="cl"><span class="nf">rroll</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="n">d20</span> <span class="o">+</span> <span class="m">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 16 26  9</span></span></span></code></pre></div><p>Quando você aprender a usar essas quatro funções, você pode olhar as
suas variações <code>plot_*()</code> delas. Elas geram gráficos (usando o ggplot2
se ele estiver disponível) correspondendo às distribuições completas de
d/p/q e um histograma simples no caso da <code>plot_rroll()</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Densidade de 8d6</span>
</span></span><span class="line"><span class="cl"><span class="nf">droll_plot</span><span class="p">(</span><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/droll/README-unnamed-chunk-5-1.webp"/>
</figure>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Função de distribuição de 8d6</span>
</span></span><span class="line"><span class="cl"><span class="nf">proll_plot</span><span class="p">(</span><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/droll/README-unnamed-chunk-5-2.webp"/>
</figure>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Função de quantil de 8d6</span>
</span></span><span class="line"><span class="cl"><span class="nf">qroll_plot</span><span class="p">(</span><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/droll/README-unnamed-chunk-5-3.webp"/>
</figure>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Histograma de 1000 rolagens de 8d6</span>
</span></span><span class="line"><span class="cl"><span class="nf">rroll_plot</span><span class="p">(</span><span class="m">1000</span><span class="p">,</span> <span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/droll/README-unnamed-chunk-5-4.webp"/>
</figure>
<p>Toda função p/q também tem um conveniente argumento <code>lower.tail</code> que
pode ser igual a <code>FALSE</code> para que os cálculos sejam feitos a partir da
cauda superior da distribuição.</p>
<h3 id="-estatístico">🪄 Estatístico</h3>
<p>Já que você é um veterano do R, você precisa ser capaz de dobrar o droll
à sua vontade. Se você gostaria de ver o tecido da realidade do droll,
você pode usar a função <code>r()</code> para obter uma distribuição de rolagem
completa. Se você quiser precisão máxima, você também pode impedir o
droll de converter a sua representação interna (operada pelo Ryacas)
para <em>doubles</em> com <code>precise = TRUE</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Obter a distribuição completa de 8d6</span>
</span></span><span class="line"><span class="cl"><span class="nf">r</span><span class="p">(</span><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 41 × 4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    outcome     n           d           p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;      &lt;dbl&gt; &lt;dbl&gt;       &lt;dbl&gt;       &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1       8     1 0.000000595 0.000000595</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2       9     8 0.00000476  0.00000536</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3      10    36 0.0000214   0.0000268</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4      11   120 0.0000714   0.0000982</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5      12   330 0.000196    0.000295</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6      13   792 0.000472    0.000766</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7      14  1708 0.00102     0.00178</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8      15  3368 0.00201     0.00379</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9      16  6147 0.00366     0.00745</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10      17 10480 0.00624     0.0137</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 31 more rows</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Poder ilimitado</span>
</span></span><span class="line"><span class="cl"><span class="nf">r</span><span class="p">(</span><span class="m">8</span> <span class="o">*</span> <span class="n">d6</span><span class="p">,</span> <span class="n">precise</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 41 × 4</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    outcome n     d          p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;      &lt;dbl&gt; &lt;chr&gt; &lt;chr&gt;      &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1       8 1     1/1679616  1/1679616</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2       9 8     1/209952   1/186624</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3      10 36    1/46656    5/186624</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4      11 120   5/69984    55/559872</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5      12 330   55/279936  55/186624</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6      13 792   11/23328   143/186624</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7      14 1708  427/419904 2995/1679616</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8      15 3368  421/209952 707/186624</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9      16 6147  683/186624 695/93312</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10      17 10480 655/104976 11495/839808</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # … with 31 more rows</span></span></span></code></pre></div><p>A tabela retornada por <code>r()</code> pode ser usada no lugar do argumento <code>roll</code>
de todas as funções discutidas acima. Isso pula os cálculos internos, um
atalho valioso se você quiser rodar múltiplos diagnósticos para a mesma
expressão de rolagem.</p>
<p>Como um estatístico nível 20, você também não está limitado pelos dados
internos do droll. Você pode criar dados personalizados usando a mesma
função <code>d()</code> descrita anteriormente.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar um dado &#34;fudge&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">dF</span> <span class="o">&lt;-</span> <span class="nf">d</span><span class="p">(</span><span class="m">-1</span><span class="o">:</span><span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">rroll</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="n">dF</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] -1  1  1 -1 -1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Criar um 2d20kh, um &#34;dado de vantagem&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">df</span> <span class="o">&lt;-</span> <span class="nf">r</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">d20</span><span class="p">,</span> <span class="n">d20</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">kh</span> <span class="o">&lt;-</span> <span class="nf">d</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">outcome</span><span class="p">,</span> <span class="n">df</span><span class="o">$</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nf">rroll</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="n">kh</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 12  5  9  5 18</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Rlang para filhotes</title>
      <link>https://lente.dev/posts/rlang-nse/</link>
      <pubDate>Tue, 27 Jul 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/rlang-nse/</guid>
      <description>Um tutorial sobre {rlang} que vai do básico ao avançado. Zero to hero!</description>
      <content:encoded><![CDATA[<p>Este é um tutorial sobre o pacote <code>{rlang}</code>, um dos mais poderosos e
menos conhecidos do R. Ele é vital para a notação compacta do
<code>{tidyverse}</code>, conhecida como <strong>tidy eval</strong>, mas mesmo assim poucas
pessoas sabem como ele funciona e como utilizá-lo para criar funções no
estilo tidy.</p>
<p>O tutorial não é curto, mas fizemos o nosso melhor para começar com
calma e terminar com colinhas para facilitar o uso deste material no dia
a dia. Se for necessário, leia e releia uma mesma seção para ter certeza
de que o conceito apresentado foi completamente absorvido. No caso de
dúvidas, entre em contato conosco e com o resto da comunidade R no nosso
<a href="https://discourse.curso-r.com/">Discourse</a>.</p>
<p>Se estiver com preguiça, deixei uma colinha no final do post. Mas, para
os corajosos, preparem-se para alguns novos conceitos de programação,
vários filhotes de cachorro e muito <code>{rlang}</code>!</p>
<h2 id="o-melhor-amigo-do-r">O melhor amigo do R</h2>
<p>A analogia que vamos usar para explicar o <code>{rlang}</code> gira em torno de um
parque repleto de filhotes fofinhos. Nós temos uma única missão nesse
parque: fazer carinho nos cachorros. Para isso, temos uma função
<code>carinho()</code> que recebe o nome de um filhote e imprime uma frase
explicando em quem estamos fazendo carinho. O objeto que descreve o
filhote se resume a uma string com a sua cor.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rex</span> <span class="o">&lt;-</span> <span class="s">&#34;laranja&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nf">carinho</span><span class="p">(</span><span class="n">rex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Fazendo carinho no filhote laranja</span></span></span></code></pre></div><p>Para facilitar a compreensão do código, vamos também ilustrar esse
cenário. Na figura abaixo, note que é criado um objeto <code>rex</code> que recebe
a figura de um filhote laranja. A função <code>carinho()</code> é retratada como
uma mão parada que, quando executada, retorna uma mão fazendo carinho no
filhote de cor apropriada (essencialmente a string retornada pelo código
acima).</p>
<figure><img src="https://lente.dev/posts/rlang-nse/01_pat_rex.webp"/>
</figure>
<h3 id="expressões">Expressões</h3>
<p>Agora que temos uma base sólida para a analogia, podemos introduzir o
primeiro conceito importante do <code>{rlang}</code>: <strong>expressões</strong>. Uma expressão
no R não passa do código antes antes que ele seja avaliado, ou seja,
aquilo que você escreve e que, depois de executado no console do
RStudio, se torna um resultado. Em quase 100% dos casos, o R não faz
nenhuma distinção entre a expressão e o valor que ela retorna, de modo
que executar <code>carinho(rex)</code> fica equivalente a executar
<code>carinho(&quot;laranja&quot;)</code>. Esse comportamento é chamado de <strong>avaliação
ansiosa</strong>, justamente porque o R avalia cada parte da expressão tão cedo
quanto for possível.</p>
<p>Essa, entretanto, não é única forma de avaliação. Também é possível
capturar uma expressão, “impedindo” o R de avaliá-la, em um processo
denominado <strong>avaliação preguiçosa</strong>. A função do <code>{rlang}</code> que faz isso
se chama <code>expr()</code> e ela retorna a expressão passada, vulgo o código
escrito.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">e</span> <span class="o">&lt;-</span> <span class="nf">expr</span><span class="p">(</span><span class="nf">carinho</span><span class="p">(</span><span class="n">max</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">e</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; carinho(max)</span></span></span></code></pre></div><p>Veja que não importa que não existe ainda um filhote chamado <code>max</code>! Como
estamos lidando apenas com uma expressão sem contexto, isso é
perfeitamente possível.</p>
<p>Voltando para o nosso parque de cachorros, a avaliação preguiçosa se
torna quase uma promessa de fazer carinho em um filhote. Temos toda a
informação necessária (no caso, o nome do filhote), mas não
transformamos isso na ação de fazer carinho: não “chamamos o filhote
para perto” para acariciá-lo. Perceba que na figura abaixo não há as
marcas de movimento da mão, pois estamos congelando a cena antes de o
filhote vir até nós.</p>
<figure><img src="https://lente.dev/posts/rlang-nse/02_expr.webp"/>
</figure>
<h3 id="ambientes">Ambientes</h3>
<p>Na nossa analogia, o próximo conceito representa o parque em si, um
lugar onde há uma correspondência entre nomes de cachorros. No R, um
<strong>ambiente</strong> funciona como um dicionário que contém definições de
objetos acompanhados pelos valores que eles carregam.</p>
<p>Abaixo, vamos “trazer” dois novos cachorros para o parque, ou seja,
criar dois novos objetos. A função <code>env_print()</code> mostra todas as
correspondências presentes no ambiente (incluindo a da função
<code>carinho()</code>), além de algumas informações extras que não nos interessam
agora.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">max</span> <span class="o">&lt;-</span> <span class="s">&#34;marrom&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">dex</span> <span class="o">&lt;-</span> <span class="s">&#34;bege&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nf">env_print</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; &lt;environment: global&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; parent: &lt;environment: package:rlang&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; bindings:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * rex: &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * e: &lt;language&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * mtcars: &lt;tibble[,11]&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * carinho: &lt;fn&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * dex: &lt;chr&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  * max: &lt;chr&gt;</span></span></span></code></pre></div><p>Na analogia, estamos colocando os cachorros <code>max</code> e <code>dex</code> no parque,
permitindo que possamos eventualmente fazer carinho neles. Vamos apenas
ignorar a definição da função <code>carinho()</code> para que isso não atrapalhe o
resto da explicação.</p>
<figure><img src="https://lente.dev/posts/rlang-nse/03_env.webp"/>
</figure>
<p>Perceba que o resultado da avaliação de uma expressão depende
completamente do ambiente. Na hora de executar um código, o R procura as
definições de todos os objetos no ambiente e os substitui dentro da
expressão. Agora vamos ver o que aconteceria se tentássemos fazer
carinho no filhote chamado <code>max</code> em outro parque…</p>
<h3 id="avaliando-expressões">Avaliando expressões</h3>
<p><strong>Avaliação nua</strong> (<em>bare evaluation</em> no original) é o processo pelo qual
o <code>{rlang}</code> permite que forneçamos explicitamente um ambiente no qual
avaliar uma expressão. É como se pudéssemos escolher o parque no qual
vamos chamar um filhote para acariciá-lo.</p>
<p>No código abaixo vamos visitar um outro parque, isto é, criar uma
função. O ambiente dentro de uma função herda as definições do ambiente
global, mas podemos fazer alterações lá dentro que não são propagadas
para fora. Vide a função abaixo: <code>p()</code> define um objeto <code>max</code> com a cor
verde e avalia (ou seja, executa) uma expressão lá dentro.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">max</span> <span class="o">&lt;-</span> <span class="s">&#34;verde&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">eval_tidy</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Seguindo a analogia dos filhotes, é como se visitássemos um outro parque
onde há um cachorro chamado <code>max</code> cuja cor é verde (além dos outros dois
cachorros que já havíamos visto no parque antigo).</p>
<figure><img src="https://lente.dev/posts/rlang-nse/04_fun.webp"/>
</figure>
<p>Como a função <code>eval_tidy()</code>, por padrão, utiliza o ambiente corrente
para avaliar expressões, então <code>p(e)</code> deve indicar carinho em um filhote
verde e não mais em um filhote marrom. Note que, apesar de não estarmos
passando um ambiente explicitamente para a <code>eval_tidy()</code>, ela está
obtendo esse ambiente através de <code>caller_env()</code>, o valor padrão para seu
argumento <code>env</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">p</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Fazendo carinho no filhote verde</span></span></span></code></pre></div><p>Na ilustração a seguir vemos o que aconteceria no nosso parque. Apesar
de estarmos chamando o nome do cachorro marrom, como estamos em outro
parque (uma nova função), o cachorro que responderá ao chamado aqui é
verde!</p>
<figure><img src="https://lente.dev/posts/rlang-nse/05_eval_expr.webp"/>
</figure>
<h3 id="quosures">Quosures</h3>
<p>Agora que você entende o que é uma expressão, o que é um ambiente e como
podemos avaliar uma expressão dentro de um ambiente, chegou a hora de
entender a estrutura mais importante do <code>{rlang}</code>: as <strong>quosures</strong>. Esse
nome estranho vem de <em>quote</em> e <em>closure</em>, dois conceitos extremamente
importantes da Ciência da Computação, mas explicar o que eles significam
foge do escopo deste tutorial.</p>
<p>Uma quosure, apesar de parecer um conceito complexo, não passa de uma
expressão que carrega um apontador para seu ambiente consigo. Isso não
parece ser muito útil, mas é a quosure que permite que as funções do
<code>{tidyverse}</code> sejam capazes de acessar as colunas de uma tabela e
variáveis declaradas no ambiente global.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">q</span> <span class="o">&lt;-</span> <span class="nf">quo</span><span class="p">(</span><span class="nf">carinho</span><span class="p">(</span><span class="n">max</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">q</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; &lt;quosure&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; expr: ^carinho(max)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; env:  global</span></span></span></code></pre></div><p>Pensando nos filhotes, uma quosure é a promessa de fazer carinho em um
cachorro sabendo exatamente o endereço do parque em que ele estava Note
que, na saída acima, o <code>env</code> se chama “global”, justamente porque
estamos trabalhando diretamente na sessão base do R.</p>
<p>Na figura abaixo, juntamente da cena retratada na ilustração sobre
expressões, vemos um qualificador de <code>max</code>, especificando onde devemos
encontrar ele. Isso é significativamente diferente de simplesmente
gritar pelo <code>max</code> mais próximo.</p>
<figure><img src="https://lente.dev/posts/rlang-nse/06_quo.webp"/>
</figure>
<h3 id="avaliando-quosures">Avaliando quosures</h3>
<p>Assim como utilizamos a avaliação nua para obter o resultado de uma
expressão em um certo ambiente, podemos usar a <strong>avaliação tidy</strong> (de
<em>tidy evaluation</em>) para obter o resultado de uma quosure no ambiente que
ela carrega.</p>
<p>Aqui, depois de capturar a quosure, podemos fazer o que quisermos com o
ambiente na qual avaliaremos ela, pois o único ambiente que importará na
avaliação tidy é o de seu ambiente de origem. Sendo assim, perceba que o
argumento <code>env</code> de <code>eval_tidy()</code> não foi levado em conta!</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">p</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Fazendo carinho no filhote marrom</span></span></span></code></pre></div><p>É difícil traduzir esse processo para a analogia dos filhotes, mas seria
algo como voltar para o endereço do parque original antes de fazer
carinho no filhote cujo nome é <code>max</code>.</p>
<figure><img src="https://lente.dev/posts/rlang-nse/07_eval_quo.webp"/>
</figure>
<h3 id="bang-bang">Bang-bang</h3>
<p>A peça final do quebra-cabeça do <code>{rlang}</code> é o <strong>bang-bang</strong>, também
conhecido como quasiquotation e expresso na forma de duas exclamações:
<code>!!</code>. Essa funcionalidade, exclusiva ao <code>{rlang}</code>, permite que façamos
uma “avaliação ansiosa seletiva” em uma expressão ou quosure. Em breve
ficará mais claro onde isso pode ser útil, mas antes é necessário ver
como usar o bang-bang na prática.</p>
<p>O bang-bang “força” a avaliação de uma parte da expressão, liberando o R
para fazer parte do seu trabalho de avaliação ansiosa. Veja, no código
abaixo, como funciona a captura de uma expressão que usa o bang-bang.
Atente-se para o fato de que, na seção anterior, alteramos o valor de
<code>max</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">expr</span><span class="p">(</span><span class="nf">carinho</span><span class="p">(</span><span class="o">!!</span><span class="n">max</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; carinho(&#34;marrom&#34;)</span></span></span></code></pre></div><p>Na analogia dos filhotes, o bang-bang está essencialmente chamando um
cachorro pelo nome antes que façamos carinho nele. Ao invés do contorno
branco que vimos nas ilustrações sobre expressões e quosures, agora
vemos a mão parada ao lado de um filhote específico.</p>
<figure><img src="https://lente.dev/posts/rlang-nse/08_bang_bang.webp"/>
</figure>
<h2 id="de-volta-para-casa">De volta para casa</h2>
<p>Apesar de termos visto um pouco de código R na sessão anterior, agora é
necessário aprofundar um pouco os exemplos. Prometo que não será nada
muito difícil, mas é impossível entender como aplicar o <code>{rlang}</code> no
mundo real sem ver alguns casos de uso.</p>
<p>Na maior parte das ocasiões, não usaremos nenhuma das funções vistas até
agora, salvo pelo bang-bang (que na verdade não é uma função, mas sim
uma sintaxe). O principal uso do <code>{rlang}</code>, na verdade, é capturar
código que o <strong>usuário</strong> escreve, então é necessário conhecer novas
versões de <code>expr()</code> e <code>quo()</code> que são capazes de capturar expressões e
quosures vindas de fora de uma função.</p>
<h3 id="enriquecimento">Enriquecimento</h3>
<p>O conceito de <strong>enriquecimento</strong> vem de uma analogia meio ruim criada
pelo autor do <code>{rlang}</code>; para simplificar, pense que as versões
enriquecidas de <code>expr()</code> e <code>quo()</code> são mais “fortes” que as versões
normais, sendo capazes de sair de dentro de uma função para capturar
expressões do lado de fora.</p>
<p>Abaixo é possível ver uma função que tenta capturar o nome de um
filhote, mas é incapaz de fazê-lo por causa da avaliação ansiosa do R. O
correto seria capturar a expressão escrita pelo usuário e imprimí-la
como uma string.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">nome1</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">filhote</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cat</span><span class="p">(</span><span class="s">&#34;O nome do filhote é&#34;</span><span class="p">,</span> <span class="n">filhote</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">nome1</span><span class="p">(</span><span class="n">dex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; O nome do filhote é bege</span></span></span></code></pre></div><p>Podemos ver a versão correta da função desejada em <code>nome2()</code>. Ela
captura a expressão do usuário com <code>enexpr()</code> (a versão enriquecida de
<code>expr()</code>) e converte esse objeto em uma string com <code>expr_text()</code>,
permitindo que a função imprima o nome do filhote.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">nome2</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">filhote</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">nome</span> <span class="o">&lt;-</span> <span class="nf">enexpr</span><span class="p">(</span><span class="n">filhote</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cat</span><span class="p">(</span><span class="s">&#34;O nome do filhote é&#34;</span><span class="p">,</span> <span class="nf">expr_text</span><span class="p">(</span><span class="n">nome</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">nome2</span><span class="p">(</span><span class="n">dex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; O nome do filhote é dex</span></span></span></code></pre></div><p>Como não havia necessidade nenhuma de capturar o ambiente do usuário
nesse exemplo, usamos apenas <code>enexpr()</code>. Na maioria das situações,
entretanto, é preciso usar <code>enquo()</code> para obter o comportamento correto.
Já que quosures incluem expressões, <code>expr()</code> e <code>enexpr()</code> quase nunca
são estritamente necessárias, então vamos simplificar tudo e seguir
apenas com as quosures.</p>
<p>No código abaixo a função <code>explica()</code> precisa tanto da expressão quanto
do ambiente da mesma, ou seja, da quosure escrita pelo usuário.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">explica</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">acao</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">quosure</span> <span class="o">&lt;-</span> <span class="nf">enquo</span><span class="p">(</span><span class="n">acao</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cat</span><span class="p">(</span><span class="s">&#34;`&#34;</span><span class="p">,</span> <span class="nf">quo_text</span><span class="p">(</span><span class="n">quosure</span><span class="p">),</span> <span class="s">&#34;` retorna:\n&#34;</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">eval_tidy</span><span class="p">(</span><span class="n">quosure</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">explica</span><span class="p">(</span><span class="nf">carinho</span><span class="p">(</span><span class="n">dex</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; `carinho(dex)` retorna:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Fazendo carinho no filhote bege</span></span></span></code></pre></div><p>Preste bastante atenção em <code>explica()</code>, pois pode ser que não seja fácil
entender como ela funciona. A primeira função utilizada é a <code>enquo()</code>
(<code>quo()</code> enriquecida), que captura a expressão do usuário juntamente com
o seu ambiente. A seguir, temos apenas que converter a quosure em string
com <code>quo_text()</code> para poder imprimí-la. O último passo é avaliar a
quosure para obter um resultado exatamente igual ao que o usuário
obteria se decidisse executar a expressão passada como argumento.</p>
<h3 id="curly-curly">Curly-curly</h3>
<p>A combinação da <code>enquo()</code> com o bang-bang é justamente a forma correta
de implementar funções que trabalham com o <code>{tidyverse}</code>. A função
<code>summarise()</code>, por exemplo, não passa de um <code>enquo()</code> disfarçado, o que
quer dizer que podemos usar o bang-bang para “injetar” o nome de uma
variável dentro de um cálculo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media1</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">var</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="n">var</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media1</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="n">cyl</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Error: Problem with `summarise()` column `resultado`.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ℹ `resultado = mean(var)`.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; x object &#39;cyl&#39; not found</span></span></span></code></pre></div><p>O código acima, que não usa bang-bang, retorna um erro. O problema é que
a <code>summarise()</code> está tentando tirar a média de um objeto chamado <code>var</code>,
que carrega um objeto chamado <code>cyl</code>, que simplesmente não existe no
ambiente global. Abaixo, usando bang-bang e <code>enquo()</code>, o código funciona
como esperado porque <code>mean(!!var)</code> se torna <code>mean(cyl)</code> dentro da
<code>summarise()</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media2</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">var</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="o">&lt;-</span> <span class="nf">enquo</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="o">!!</span><span class="n">var</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media2</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="n">cyl</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   resultado</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1      6.19</span></span></span></code></pre></div><p>O <code>{tidyverse}</code> nos fornece um atalho para essa combinação poderosa de
<code>enquo()</code> com <code>!!</code>: o <code>{{ }}</code>, mais conhecido como <strong>curly-curly</strong>.
Agora que você já entende exatamente o que está acontecendo por trás dos
panos, saber onde usar o curly-curly é mais fácil.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media3</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">var</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">({{</span><span class="n">var</span><span class="p">}}))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media3</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="n">cyl</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   resultado</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1      6.19</span></span></span></code></pre></div><h3 id="splice">Splice</h3>
<p>A penúltima funcionalidade do <code>{rlang}</code> a compreender é o conceito de
<strong>splice</strong> (“emendar” em português), que se manifesta nas versões
pluralizadas das funções apresentadas até agora. Essencialmente,
<code>expr()/enexpr</code> e <code>quo()/enquo()</code> só conseguem lidar com uma única
expressão ou quosure, então temos outras versões para trabalhar com
múltiplas expressões ou quosures.</p>
<p>Na prática, a principal função que utilizaremos é <code>enquos()</code>. Ela
captura todo o conteúdo de uma <strong>elipse</strong> e o transforma em uma lista de
quosures como no exemplo abaixo. As versões plurais também acompanham o
<strong>bang-bang-bang</strong>, o irmão com splice do bang-bang.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media4</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="kc">...</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">vars</span> <span class="o">&lt;-</span> <span class="nf">enquos</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="nf">across</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="o">!!!</span><span class="n">vars</span><span class="p">),</span> <span class="n">mean</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media4</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="n">cyl</span><span class="p">,</span> <span class="n">disp</span><span class="p">,</span> <span class="n">hp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 3</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;     cyl  disp    hp</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1  6.19  231.  147.</span></span></span></code></pre></div><p>Se você não estiver familiarizado com a <code>across()</code>, basta saber apenas
que o primeiro argumento é um vetor de colunas (similar ao que
passaríamos para <code>select()</code>) e o segundo é uma função para utilizar no
resumo das colunas especificadas. Aqui o <code>!!!</code> está apenas transformando
a chamada em <code>across(c(cyl, disp, hp), mean)</code>.</p>
<h3 id="símbolos">Símbolos</h3>
<p>Existe ainda um conceito que não abordamos até agora: <strong>símbolos</strong>. Um
símbolo não passa do nome de um objeto, ou seja, <code>rex</code>, <code>max</code> e <code>dex</code> na
analogia dos filhotes; mais especificamente, um símbolo é uma expressão
com algumas restrições sobre o seu conteúdo. A função <code>sym()</code>,
especificamente, transforma uma string em um símbolo, permitindo que ela
seja usada junto com outras expressões.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media6</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">var</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="o">&lt;-</span> <span class="nf">ensym</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="o">!!</span><span class="n">var</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media6</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="s">&#34;cyl&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   resultado</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1      6.19</span></span></span></code></pre></div><h3 id="miscelânea">Miscelânea</h3>
<p>Fora os vários conceitos já apresentados, restam apenas duas breves
considerações para praticamente zerar o <code>{rlang}</code>:</p>
<ol>
<li>
<p>O curly-curly funciona com strings, mas não com splice, então a
família <code>sym()</code> torna-se quase desnecessária juntamente com o <code>!!</code>
ao mesmo tempo em que o <code>!!!</code> permanece essencial.</p>
</li>
<li>
<p>Há um operador específico (<code>:=</code>, chamado de <strong>morsa</strong>) para quando
precisamos forçar a execução de algo no lado esquerdo de um cálculo,
mesmo quando usando o curly-curly.</p>
</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">media7</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">col</span><span class="p">,</span> <span class="kc">...</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">args</span> <span class="o">&lt;-</span> <span class="nf">enquos</span><span class="p">(</span><span class="kc">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="p">{{</span><span class="n">col</span><span class="p">}}</span> <span class="o">:=</span> <span class="nf">mean</span><span class="p">(</span><span class="o">!!!</span><span class="n">args</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">media7</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="s">&#34;nova_coluna&#34;</span><span class="p">,</span> <span class="n">drat</span><span class="p">,</span> <span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 1 × 1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   nova_coluna</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;         &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1        3.60</span></span></span></code></pre></div><h2 id="de-volta-para-o-trabalho">De volta para o trabalho</h2>
<p>Depois de tanto conteúdo, agora você consegue entender as colinhas que
apresentamos abaixo para facilitar o seu uso do <code>{rlang}</code> no dia-a-dia.
Ao final também deixamos as referências deste tutorial para que você
possa aprofundar ainda mais os seus conhecimentos de tidy eval.</p>
<h3 id="vocabulário">Vocabulário</h3>
<table>
<thead>
<tr>
<th style="text-align:left">Vocábulo</th>
<th style="text-align:left">Tradução</th>
<th style="text-align:left">Significado</th>
<th style="text-align:left">Código</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Ambiente</td>
<td style="text-align:left"><em>Environment</em></td>
<td style="text-align:left">Dicionário de nomes e valores</td>
<td style="text-align:left"><code>env()</code></td>
</tr>
<tr>
<td style="text-align:left">Avaliação ansiosa</td>
<td style="text-align:left"><em>Eager evaluation</em></td>
<td style="text-align:left">Avaliação de todo objeto o mais rápido possível</td>
<td style="text-align:left">-</td>
</tr>
<tr>
<td style="text-align:left">Avaliação nua</td>
<td style="text-align:left"><em>Bare evaluation</em></td>
<td style="text-align:left">Avaliação que necessita de um ambiente passado explicitamente</td>
<td style="text-align:left"><code>eval_tidy(e)</code></td>
</tr>
<tr>
<td style="text-align:left">Avaliação preguiçosa</td>
<td style="text-align:left"><em>Lazy evaluation</em></td>
<td style="text-align:left">Avaliação de cada objeto conforme a necessidade</td>
<td style="text-align:left"><code>quo()</code>, etc.</td>
</tr>
<tr>
<td style="text-align:left">Avaliação tidy</td>
<td style="text-align:left"><em>Tidy evaluation</em></td>
<td style="text-align:left">Avaliação que utiliza o ambiente da quosure</td>
<td style="text-align:left"><code>eval_tidy(q)</code></td>
</tr>
<tr>
<td style="text-align:left">Bang-bang</td>
<td style="text-align:left"><em>Bang-bang</em></td>
<td style="text-align:left">Operador utilizado para forçar a avaliação de um objeto</td>
<td style="text-align:left"><code>!!</code></td>
</tr>
<tr>
<td style="text-align:left">Bang-bang-bang</td>
<td style="text-align:left"><em>Bang-bang-bang</em></td>
<td style="text-align:left">Operador utilizado para forçar a avaliação de vários objetos</td>
<td style="text-align:left"><code>!!!</code></td>
</tr>
<tr>
<td style="text-align:left">Curly-curly</td>
<td style="text-align:left"><em>Curly-curly</em></td>
<td style="text-align:left">Atalho para <code>enquo()</code> + <code>!!</code></td>
<td style="text-align:left"><code>{{ }}</code></td>
</tr>
<tr>
<td style="text-align:left">Elipse</td>
<td style="text-align:left"><em>Ellipsis</em></td>
<td style="text-align:left">Argumento de uma funcão que pode receber múltiplas entradas</td>
<td style="text-align:left"><code>...</code></td>
</tr>
<tr>
<td style="text-align:left">Enriquecimento</td>
<td style="text-align:left"><em>Enriching</em></td>
<td style="text-align:left">Processo que permite a captura de código do usuário</td>
<td style="text-align:left"><code>enquo()</code>, etc.</td>
</tr>
<tr>
<td style="text-align:left">Expressão</td>
<td style="text-align:left"><em>Expression</em></td>
<td style="text-align:left">Código R antes de avaliado</td>
<td style="text-align:left"><code>expr()</code></td>
</tr>
<tr>
<td style="text-align:left">Morsa</td>
<td style="text-align:left"><em>Walrus</em></td>
<td style="text-align:left">Operador utilizado para permitir expressões do lado esquerdo de uma igualdade</td>
<td style="text-align:left"><code>:=</code></td>
</tr>
<tr>
<td style="text-align:left">Quosure</td>
<td style="text-align:left"><em>Quosure</em></td>
<td style="text-align:left">Expressão que carrega seu ambiente consigo</td>
<td style="text-align:left"><code>quo()</code></td>
</tr>
<tr>
<td style="text-align:left">Símbolo</td>
<td style="text-align:left"><em>Symbol</em></td>
<td style="text-align:left">Expressão que pode representar apenas o nome de um objeto</td>
<td style="text-align:left"><code>sym()</code></td>
</tr>
<tr>
<td style="text-align:left">Splice</td>
<td style="text-align:left"><em>Splice</em></td>
<td style="text-align:left">Processo que permite a captura de múltiplas expressões, etc.</td>
<td style="text-align:left"><code>quos()</code>, etc.</td>
</tr>
</tbody>
</table>
<h3 id="principais-funções">Principais funções</h3>
<table>
<thead>
<tr>
<th style="text-align:left">Objeto</th>
<th style="text-align:left">Simples</th>
<th style="text-align:left">Enriquecido</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Símbolo</td>
<td style="text-align:left"><code>sym()/syms()</code></td>
<td style="text-align:left"><code>ensym()/ensyms()</code></td>
</tr>
<tr>
<td style="text-align:left">Expressão</td>
<td style="text-align:left"><code>expr()/exprs()</code></td>
<td style="text-align:left"><code>enexpr()/enexprs()</code></td>
</tr>
<tr>
<td style="text-align:left">Quosure</td>
<td style="text-align:left"><code>quo()/quos()</code></td>
<td style="text-align:left"><code>enquo()/enquos()</code></td>
</tr>
</tbody>
</table>
<h3 id="principais-padrões">Principais padrões</h3>
<p>Os padrões incluem dois exemplos que não foram explicados durante o
tutorial. Para saber mais, consulte as referências no final do texto.</p>
<table>
<thead>
<tr>
<th style="text-align:left">Descrição</th>
<th style="text-align:left">Usuário</th>
<th style="text-align:left">Programador</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Expressão do lado esquerdo</td>
<td style="text-align:left"><code>media(df, col)</code></td>
<td style="text-align:left"><code>{{col}} := mean(var)</code></td>
</tr>
<tr>
<td style="text-align:left">Expressão do lado direito</td>
<td style="text-align:left"><code>media(df, var)</code></td>
<td style="text-align:left"><code>col = mean({{var}})</code></td>
</tr>
<tr>
<td style="text-align:left">Expressões do lado direito</td>
<td style="text-align:left"><code>media(df, var, arg1 = 0)</code></td>
<td style="text-align:left"><code>col = mean(!!!var)</code></td>
</tr>
<tr>
<td style="text-align:left">Expressões no meio</td>
<td style="text-align:left"><code>agrupar(df, var1, var2)</code></td>
<td style="text-align:left"><code>group_by(df, ...)</code></td>
</tr>
<tr>
<td style="text-align:left">Símbolo do lado esquerdo</td>
<td style="text-align:left"><code>media(df, &quot;col&quot;)</code></td>
<td style="text-align:left"><code>{{col}} := mean(var)</code></td>
</tr>
<tr>
<td style="text-align:left">Símbolo do lado direito</td>
<td style="text-align:left"><code>media(df, &quot;var&quot;)</code></td>
<td style="text-align:left"><code>col = mean(.data$var)</code></td>
</tr>
</tbody>
</table>
<h3 id="referências">Referências</h3>
<ul>
<li>
<p><a href="https://adv-r.hadley.nz/metaprogramming.html"><em>Advanced R: Metaprogramming</em></a></p>
</li>
<li>
<p><a href="https://rlang.r-lib.org/">Documentação do <code>{rlang}</code></a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=o5_Df-btuD4"><em>Programando com o tidyverse: introdução ao pacote rlang</em></a></p>
</li>
<li>
<p><a href="https://dplyr.tidyverse.org/articles/programming.html"><em>Programming with dplyr</em></a></p>
</li>
<li>
<p><a href="https://raw.githubusercontent.com/rstudio/cheatsheets/master/tidyeval.pdf"><em>Tidy evaluation with rlang: Cheat Sheet</em></a></p>
</li>
<li>
<p><a href="https://ggplot2.tidyverse.org/articles/ggplot2-in-packages.html"><em>Using ggplot2 in packages</em></a></p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>O novo pipe chegou</title>
      <link>https://lente.dev/posts/novo-pipe/</link>
      <pubDate>Wed, 19 May 2021 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/novo-pipe/</guid>
      <description>O novo pipe e outras novidades que chegaram ao R em 18/05/2021</description>
      <content:encoded><![CDATA[<p>A profecia estava correta: o R finalmente ganhou um pipe próprio, embutido
à linguagem em si. Mais de 7 anos depois do
<a href="https://github.com/tidyverse/magrittr/commit/6f79e6dbf81a1a480c3b41c24b0dc40777981338">primeiro commit</a>
do <code>{magrittr}</code>, o <code>%&gt;%</code>, operador com o qual compartilhamos tantas boas
memórias, símbolo do R moderno e inspiração para o logo da
<a href="https://curso-r.com/">Curso-R</a>, vai se tornar obsoleto. De acordo com a
<a href="https://developer.r-project.org/">agenda</a> do R Project, no badalar da
meia-noite do dia 18/05/2021 foi lançada oficialmente a versão 4.1.0 (&ldquo;Camp
Pontanezen&rdquo;) do R, contendo, dentre outras novidades, suporte para o operador
<code>|&gt;</code>.</p>
<p>Devo admitir que estou um pouco triste com a despedida, como se eu estivesse
prestes a mudar de casa: pode ser que a casa nova seja melhor e maior, mas, de
uma forma ou de outra, estou abandonando um lugar que foi palco de várias boas
memórias por um lugar estéril e inerte&hellip;</p>
<p>Só que mesmo assim nós seguimos em frente e mudamos de casa! As lembranças não
vão embora e temos a oportunidade de criar mais boas memórias com esse novo
plano de fundo. Sendo assim, vamos entender as principais mudanças do R 4.1 e,
principalmente, como usar o novo pipe.</p>
<h2 id="o-novo-pipe-">O novo pipe: <code>|&gt;</code></h2>
<p>À primeira vista, o novo pipe é igual ao antigo: usado no final de uma linha
para passar o resultado do que está à sua esquerda como primeiro argumento da
linha debaixo. Aqui temos um exemplo simples do uso mais comum dos pipes:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Uma pipeline com o pipe novo</span>
</span></span><span class="line"><span class="cl"><span class="n">starwars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">group_by</span><span class="p">(</span><span class="n">species</span><span class="p">,</span> <span class="n">sex</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">select</span><span class="p">(</span><span class="n">species</span><span class="p">,</span> <span class="n">sex</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">height</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="n">height</span><span class="p">,</span> <span class="n">na.rm</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pull</span><span class="p">(</span><span class="n">height</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summary</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    66.0   163.0   181.3   173.5   196.0   264.0</span></span></span></code></pre></div><p>As diferenças aparecem quanto tentamos usar o <code>.</code>, a saber, o <em>dot placeholder</em>.
Bem comum no antigo pipe, o uso do <code>.</code> para escolher onde a substituição deve
ocorrer é simplesmente proibido no novo pipe. Essa decisão foi tomada porque o
<code>.</code> gera situações ambíguas como a descrita a seguir:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Vamos gerar essa string a partir de &#34;-&#34; %&gt;% paste0()</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;-&gt;&lt;-&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;-&gt;&lt;-&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Podemos começar colando o hífen na esquerda</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;-&#34;</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;&gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;-&gt;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Agora adicionamos o . para colar na direita também...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Mas isso dá errado!</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;-&#34;</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;&gt;&lt;&#34;</span><span class="p">,</span> <span class="n">.)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;&gt;&lt;-&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Precisamos colocar o . em dois lugares diferentes,</span>
</span></span><span class="line"><span class="cl"><span class="c1"># incluindo, contraintuitivamente, no primeiro argumento</span>
</span></span><span class="line"><span class="cl"><span class="s">&#34;-&#34;</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">paste0</span><span class="p">(</span><span class="n">.,</span> <span class="s">&#34;&gt;&lt;&#34;</span><span class="p">,</span> <span class="n">.)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;-&gt;&lt;-&#34;</span></span></span></code></pre></div><p>Assim, em troca de nunca mais precisar carregar o <code>{magrittr}</code>, usar
<code>usethis::use_pipe()</code> ou se preocupar com o ambiente do <code>{future}</code>, vamos ser
obrigados a criar funções parciais que sempre esperam a substituição no seu
primeiro argumento. Mas, falando em funções, chegamos à segunda maior novidade
do R 4.1&hellip;</p>
<h2 id="funções-anônimas-x">Funções anônimas: <code>\(x)</code></h2>
<p>Se você se acostumou com a notação de fórmulas do <code>{purrr}</code>, então funções
anônimas não são nada de novo. Também conhecidas como <em>lambdas</em>, funções
anônimas não passam de funções que não precisam receber um nome, ou seja, podem
ser utilizadas pelo programa na hora de sua criação. No caso do <code>{purrr}</code> isso
se dava através de uma gambiarra feita em cima das fórmulas (<code>~.x</code>), mas, ainda
assim, isso era melhor do que a sintaxe bastante prolixa que o R básico exigia
(<code>function(x) x</code>).</p>
<p>A nova sintaxe é, na minha opinião, bastante melhor que a estratégia do
<code>{purrr}</code>. Apesar de ela ser um pouco mais extensa, ela funciona em todos os
lugares (não só no tidyverse), permite nomes arbitrários para os argumentos e
não bagunça a função do <code>~</code>. A nova função anônima é declarada com uma barra
oblíqua para a esquerda seguida por todos os argumentos entre parênteses e o
código; essencialmente, é igual à notação antiga, mas <code>function</code> vira <code>\</code>. A
escolha do símbolo <code>\</code> também é ótima, pois é igual à de
<a href="https://wiki.haskell.org/Anonymous_function">outras linguagens</a> e porque lembra
um λ (lambda) com a perna cortada. Para comparar todas as diferentes notações,
segue um breve exemplo (saídas suprimidas):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">purrr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Sem função anônima</span>
</span></span><span class="line"><span class="cl"><span class="n">soma_um</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">x</span> <span class="o">+</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="n">soma_um</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A notação antiga do {base} é extensa</span>
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="n">x</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A notação do {purrr} força o .x</span>
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="o">~</span> <span class="n">.x</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A notação nova permite qualquer nome</span>
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="nf">\</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">n</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A notação nova funciona fora do tidyverse</span>
</span></span><span class="line"><span class="cl"><span class="nf">lapply</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="nf">\</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="n">x</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Para mais de 2 argumentos, o {purrr} muda</span>
</span></span><span class="line"><span class="cl"><span class="nf">pmap</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="m">11</span><span class="o">:</span><span class="m">20</span><span class="p">,</span> <span class="m">21</span><span class="o">:</span><span class="m">30</span><span class="p">),</span> <span class="o">~</span> <span class="kc">..1</span> <span class="o">+</span> <span class="kc">..2</span> <span class="o">+</span> <span class="kc">..3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A notação nova continua consistente</span>
</span></span><span class="line"><span class="cl"><span class="nf">pmap</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,</span> <span class="m">11</span><span class="o">:</span><span class="m">20</span><span class="p">,</span> <span class="m">21</span><span class="o">:</span><span class="m">30</span><span class="p">),</span> <span class="nf">\</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span><span class="p">)</span></span></span></code></pre></div><p>De quebra, na minha opinião, também será muito mais fácil de ensinar o <code>\(x)</code> do
que o <code>~.x</code>. A notação é intuitiva, consistente e funciona fora do tidyverse,
então, para mim, o novo lambda é até mais interessante do que o novo pipe!</p>
<h2 id="miscelânea">Miscelânea</h2>
<p>Para te poupar desse trabalho, eu li o
<a href="https://stat.ethz.ch/R-manual/R-devel/doc/html/NEWS.html">NEWS</a> da nova versão
a fim de saber quais são as novidades mais interessantes do 4.1. Fora o novo
pipe e o novo lambda, achei algumas coisas dignas de nota:</p>
<ul>
<li>
<p>Usar <code>c()</code> para combinar fatores agora retorna um fator que também combina
todos os níveis (de forma similar ao <code>forcats::fct_c()</code>);</p>
</li>
<li>
<p><code>apply()</code> agora tem um argumento <code>simplify</code> para desabilitar a simplificação
de resultados;</p>
</li>
<li>
<p>O novo utilitário <code>...names()</code> retorna os nomes dos argumentos passados via
<code>...</code> (possivelmente facilitando o trabalho do <code>{tidyselect}</code>);</p>
</li>
<li>
<p>As funções <code>URLencode()</code> e <code>URLdecode()</code> agora funcionam com vetores de URIs;</p>
</li>
<li>
<p><code>grep()</code>, <code>sub()</code>, <code>regexp()</code>, etc. ficaram mais rápidas para fatores longos
com poucos níveis e</p>
</li>
<li>
<p><code>duplicated()</code> e <code>anyDuplicated()</code> agora são otimizados para vetores numéricos
já ordenados via ALTREP.</p>
</li>
</ul>
<h2 id="conclusão">Conclusão</h2>
<p>Se você não consegue esperar para testar as novas funcionalidades, já é possível
baixar a versão beta do R 4.1 diretamente do
<a href="https://cran.r-project.org/src/base-prerelease/">site</a> do R Project. O time do
R Core apenas pede que você
<a href="https://developer.r-project.org/Blog/public/2021/04/28/r-can-use-your-help-testing-r-before-release/">reporte</a>
quaisquer bugs detectados!</p>
<p>Para quem é mais paciente e prefere esperar o lançamento oficial na sua plataforma
de preferência, abra o seu RStudio, aperte CTRL + SHIFT + M com carinho e agradeça por
todas as aventuras patrocinadas pelo pipe. O pacote <code>{magrittr}</code> continuará lá,
funcionando, mas cada vez menos relevante&hellip; Apesar de estarmos entrando em uma
nova fase do R, as lembranças e aprendizados do passado nunca irão embora.</p>
<p>%&gt;%</p>
]]></content:encoded>
    </item>
    <item>
      <title>Stockfish no R</title>
      <link>https://lente.dev/posts/stockfish/</link>
      <pubDate>Tue, 15 Dec 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/stockfish/</guid>
      <description>Um pacote R para analisar jogos de xadrez com o Stockfish</description>
      <content:encoded><![CDATA[<p><code>{stockfish}</code> é um pacote R que implementa o protocolo aberto de comunicação
<a href="http://wbec-ridderkerk.nl/html/UCIProtocol.html">UCI</a> e acompanha uma
instalação do <a href="https://github.com/official-stockfish/Stockfish">Stockfish 11</a>,
um motor de xadrez muito popular, open source e poderoso escrito em C++.</p>
<h2 id="instalação">Instalação</h2>
<p>Instale a versão estável do <code>{stockfish}</code> do CRAN:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;stockfish&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Ou instale a versão em desenvolvimento do
<a href="https://github.com/curso-r/stockfish">GitHub</a> com:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># install.packages(&#34;remotes&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">remotes</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;curso-r/stockfish&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Você também pode encontrar mais (e mais recentes) versões do motor Stockfish
para usar com o <code>{stockfish}</code> na
<a href="https://stockfishchess.org/download/">página de download</a> do projeto.</p>
<h2 id="exemplo">Exemplo</h2>
<p>É tão fácil usar o <code>{stockfish}</code> quanto qualquer outro pacote UCI. Você deve
inicializar o motor com <code>fish$new()</code> e enviar comandos com os seus métodos
internos, lembrando apenas de rodar <code>quit()</code> quando você terminar.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">stockfish</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Inicializar o motor</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span> <span class="o">&lt;-</span> <span class="n">fish</span><span class="o">$</span><span class="nf">new</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Examinar o processo em plano de fundo</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="n">process</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; PROCESS &#39;stockfish&#39;, running, pid 173670.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Procurar a melhor jogada</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="nf">go</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;bestmove e2e4 ponder d7d5&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Começar um jogo a partir de um FEN</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="nf">ucinewgame</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="nf">position</span><span class="p">(</span><span class="s">&#34;6rk/2Q3p1/5qBp/5P2/8/7P/6PK/8 w - - 15 51&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="nf">go</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;bestmove g6f7 ponder g8d8&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Finalizar o motor</span>
</span></span><span class="line"><span class="cl"><span class="n">engine</span><span class="o">$</span><span class="nf">quit</span><span class="p">()</span></span></span></code></pre></div><h2 id="uso">Uso</h2>
<p><code>fish</code>, a principal classe do pacote, representa um motor Stockfish, permitindo
que o usuário envie comandos e receba saídas de acordo com o protocolo UCI.
Resumindo, um objeto <code>fish</code>, quando criado, cria um processo Stockfish
desacoplado e faz um <em>pipe</em> com as suas entrada e saída padrões.</p>
<p>Para mais informações, veja a sua documentação completa executando <code>?fish</code>.</p>
<h3 id="stockfish-incluso">Stockfish Incluso</h3>
<p>O pacote acompanha uma instalação do
<a href="https://github.com/official-stockfish/Stockfish">Stockfish</a>, um motor de xadrez
muito popular, open source e poderoso escrito em C++. Ele consegue chegar em um
ELO de 3516, roda no Windows, macOS, Linux, iOS e Android, e pode ser compilado
em menos de um minuto.</p>
<p>Quando o <code>{stockfish}</code> (inicial minúscula) estiver sendo instalado, o
código-fonte do Stockfish (inicial maiúscula) é compilado e o executável
resultante é armazenado junto com os seus pacote R. Isso não é uma instalação
para todos os usuários! Você não precisa dar privilégios administrativos para
ele rodar ou se preocupar com qualquer software adicional.</p>
<p>O único ponto negativo é que a versão inclusa é o Stockfish 11, não a versão
mais recente (Stockfish 12). Isso ocorre porque a versão 12 precisa de downloads
adicionais, o que aumentaria dramaticamente o tempo de instalação. Se quiser,
você pode <a href="https://stockfishchess.org/download/">baixar</a> a versão de sua escolha
e passar o caminho para o executável como argumento para <code>fish$new()</code>.</p>
<h3 id="protocolo-uci">Protocolo UCI</h3>
<p>UCI (<em>Universal Chess Interface</em>) é um protocolo aberto de comunicação que
permite que motores de xadrez se comuniquem com interfaces de usuário. Na
verdade, a classe <code>fish</code> implementa o
<a href="http://wbec-ridderkerk.nl/html/UCIProtocol.html">protocolo UCI</a> como publicado
por Stefan-Meyer Kahlen, apenas com um foco no Stockfish. Isso significa que
alguns métodos não são implementados (veja <strong>Pegadinhas</strong>) e que todos os testes
são feitos com o Stockfish, mas todo o resto deveria funcionar perfeitamente com
outros motores.</p>
<p>O texto entre aspas no fim da documentação de cada método foi extraído
diretamente do protocolo UCI oficial para que você possa ver exatamente o que
aquele comando pode fazer. No geral, os comandos são bem autoexplicativos,
exceto pela LAN (<em>long algebraic notation</em>), a notação de jogadas usada pelo
UCI. Nessa notação, jogadas são registradas usando as posições inicial e final
da peça, por exemplo, e2e4, e7e5, e1g1 (roque pequeno das brancas), e7e8q
(promoção), 0000 (jogada vazia).</p>
<h3 id="implementação">Implementação</h3>
<p>Todo o trabalho duro da classe <code>fish</code> é feito pelo pacote <code>{processx}</code>. O
processo do Stockfish é criado com <code>processx::process$new</code> e a entrada/saída é
feita com <code>write_input()</code> e <code>read_output()</code>. Um aspecto importante do protocolo
de comunicação de qualquer motor UCI é esperar por respostas, e aqui isso é
feito com um loop que verifica o processo com <code>poll_io()</code> e para assim que a
saída volta vazia.</p>
<p>Antes de implementar o protocolo UCI manualmente, o pacote usava o <code>{bigchess}</code>.
Ele é um pacote incrível criado por
<a href="https://github.com/rosawojciech">@rosawojciech</a>, mas ele tem algumas
dependências que estão além do escopo do <code>{stockfish}</code> e, no final, eu queria
mais controle da API (por exemplo usando <code>{R6}</code>).</p>
<h3 id="pegadinhas">Pegadinhas</h3>
<p>A classe <code>fish</code> tem algumas idiossincrasias que o usuário deve ter em mente
quando tentar se comunicar com o Stockfish. Algumas são devidas a escolhas de
implementação, mas outras estão relacionadas ao protocolo UCI em si. Esta não
é uma lista completa (e você provavelmente deveria ler a
<a href="http://wbec-ridderkerk.nl/html/UCIProtocol.html">documentação do UCI</a>), mas
aqui vão algumas coisas para ficar de olho.</p>
<ul>
<li>
<p>Nem todos os métodos UCI foram implementados: como o <code>{stockfish}</code> foi feito
com o Stockfish (e especialmente o Stockfish 11) em mente, dois métodos do UCI
que não funcionam com o motor não foram implementados. Eles são <code>debug()</code> e
<code>register()</code>.</p>
</li>
<li>
<p>A maioria dos métodos retorna silenciosamente: como a maioria dos comandos UCI
não retornam nada ou retornam texto padrão, a maioria dos métodos retorna
silenciosamente. As exceções são <code>run()</code>, <code>isready()</code>, <code>go()</code> e <code>stop()</code>; você
pode ver exatamente o que eles retornam lendo as suas documentações.</p>
</li>
<li>
<p>Nem toda opção do Stockfish vai funcionar: pelo menos quando usando a versão
inclusa do Stockfish, nem todas as opções documentadas vão funcionar com
<code>setoption()</code>. Isso ocorre porque, como descrito acima, o pacote vem com o
Stockfish 11, que não é a versão mais recente. Opções que não vão funcionar
estão marcadas com um asterisco.</p>
</li>
<li>
<p>Tempos são em milissegundos. diferentemente da maioria das funções do R, todo
método que recebe um intervalo de tempo espera que o mesmo seja em milissegundos,
não segundos.</p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Por que usar R?</title>
      <link></link>
      <pubDate>Mon, 14 Dec 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Xadrez no R com chess</title>
      <link>https://lente.dev/posts/chess/</link>
      <pubDate>Mon, 16 Nov 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/chess/</guid>
      <description>Um pacote em R para ler, escrever, criar e explorar jogos de xadrez</description>
      <content:encoded><![CDATA[<p><code>{chess}</code> é uma interface <em>opinionada</em> em R para o
<a href="https://github.com/niklasf/python-chess">python-chess</a>, uma biblioteca incrível
criada por <a href="https://github.com/niklasf">Niklas Fiekas</a>. Ela permite que usuários
leiam e escrevam arquivos <a href="https://en.wikipedia.org/wiki/Portable_Game_Notation">PGN</a>,
além de possibilitar a criação e exploração de árvores de jogos como aquelas
presentes em livros de xadrez.</p>
<p>Este pacote ainda está amadurecendo! Então eu encorajo todos a enviar suas
sugestões e bugs em <a href="https://github.com/clente/chess/issues">issues</a> no
repositório do pacote.</p>
<h2 id="instalação">Instalação</h2>
<p>Você pode instalar a versão mais recente do <code>{chess}</code> do CRAN com:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;chess&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Isso deveria automaticamente instalar o python-chess no seu ambiente do
<code>{reticulate}</code>, mas você também pode fazer isso explicitamente com o comando:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">chess</span><span class="o">::</span><span class="nf">install_chess</span><span class="p">()</span></span></span></code></pre></div><h2 id="exemplo">Exemplo</h2>
<p>Para ler um jogo existente, basta usar <code>read_game()</code>. Para explorar ele, você
pode usar <code>forward()</code>/<code>back()</code>, assim como <code>variations()</code>/<code>variation()</code> para ver
todas as variações disponíveis para o próximo movimento e escolher uma delas.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">chess</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ler o primeiro jogo de My 60 Memorable Games</span>
</span></span><span class="line"><span class="cl"><span class="n">file</span> <span class="o">&lt;-</span> <span class="nf">system.file</span><span class="p">(</span><span class="s">&#34;m60mg.pgn&#34;</span><span class="p">,</span> <span class="n">package</span> <span class="o">=</span> <span class="s">&#34;chess&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fischer_sherwin</span> <span class="o">&lt;-</span> <span class="nf">read_game</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">n_max</span> <span class="o">=</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Posição inicial</span>
</span></span><span class="line"><span class="cl"><span class="n">fischer_sherwin</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;         &lt;Start&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; r n b q k b n r</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; p p p p p p p p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; P P P P P P P P</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; R N B Q K B N R</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Navegar para 4. g3</span>
</span></span><span class="line"><span class="cl"><span class="n">fischer_sherwin</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">forward</span><span class="p">(</span><span class="m">7</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;         &lt;4. g3&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; r . b q k b n r</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; p p . p . p p p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . n . p . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . p . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . P . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . P . N P .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; P P P . . P . P</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; R N B Q K B . R</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ver todas as variações de 4...</span>
</span></span><span class="line"><span class="cl"><span class="n">fischer_sherwin</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">forward</span><span class="p">(</span><span class="m">7</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">variations</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;      &lt;4... Nf6&gt;          &lt;4... d5&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; r . b q k b . r    r . b q k b n r</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; p p . p . p p p    p p . . . p p p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . n . p n . .    . . n . p . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . p . . . . .    . . p p . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . P . . .    . . . . P . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . P . N P .    . . . P . N P .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; P P P . . P . P    P P P . . P . P</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; R N B Q K B . R    R N B Q K B . R</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Seguir a linha auxiliar</span>
</span></span><span class="line"><span class="cl"><span class="n">fischer_sherwin</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">forward</span><span class="p">(</span><span class="m">7</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">variation</span><span class="p">(</span><span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       &lt;4... d5&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; r . b q k b n r</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; p p . . . p p p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . n . p . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . p p . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . P . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . P . N P .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; P P P . . P . P</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; R N B Q K B . R</span></span></span></code></pre></div><p>Você também pode criar o seu próprio jogo com <code>game()</code> e adicionar variações ao
mesmo: a função <code>move()</code> adiciona jogadas assim como ramos na árvore do jogo.
Strings são convertidas para jogadas simples, enquanto <code>list()</code> funciona
exatamente como os parênteses de um PGN, criando uma variação para a última
jogada. Aqui podemos ver como recriar o
<a href="https://en.wikipedia.org/wiki/Scholar%27s_mate">Mate do Pastor</a> e algumas
formas de evitá-lo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Mate do Pastor e algumas defesas</span>
</span></span><span class="line"><span class="cl"><span class="n">scholars_mate</span> <span class="o">&lt;-</span> <span class="nf">game</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;e4&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;e5&#34;</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;e6&#34;</span><span class="p">),</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;d5&#34;</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;Bc4&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;Nc6&#34;</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;Nf6&#34;</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;Qh5&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;Nf6&#34;</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;g6&#34;</span><span class="p">,</span> <span class="s">&#34;Qf3&#34;</span><span class="p">,</span> <span class="s">&#34;Nf6&#34;</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">move</span><span class="p">(</span><span class="s">&#34;Qxf7&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Última jogada da linha principal</span>
</span></span><span class="line"><span class="cl"><span class="n">scholars_mate</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;      &lt;4. Qxf7#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; r . b q k b . r</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; p p p p . Q p p</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . n . . n . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . p . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . B . P . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; P P P P . P P P</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; R N B . K . N R</span></span></span></code></pre></div><p>Note que há muitas formas de estruturar a entrada de <code>move()</code>. Veja
<code>vignette(&quot;chess&quot;)</code> para mais informações.</p>
<p><code>{chess}</code> também traz muitas formas de ver tanto o jogo como um todo, quanto o
tabuleiro em um momento específico.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Tabuleiro com unicode (não fica bonito no navegador)</span>
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">scholars_mate</span><span class="p">,</span> <span class="n">unicode</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;      &lt;4. Qxf7#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ♜ . ♝ ♛ ♚ ♝ . ♜</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ♟ ♟ ♟ ♟ . ♕ ♟ ♟</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . ♞ . . ♞ . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . ♟ . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . ♗ . ♙ . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; . . . . . . . .</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ♙ ♙ ♙ ♙ . ♙ ♙ ♙</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ♖ ♘ ♗ . ♔ . ♘ ♖</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Exportar o FEN do tabuleiro</span>
</span></span><span class="line"><span class="cl"><span class="nf">fen</span><span class="p">(</span><span class="n">scholars_mate</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;r1bqkb1r/pppp1Qpp/2n2n2/4p3/2B1P3/8/PPPP1PPP/RNB1K1NR b KQkq - 0 4&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ver o PGN depois de um movimento</span>
</span></span><span class="line"><span class="cl"><span class="nf">str</span><span class="p">(</span><span class="nf">back</span><span class="p">(</span><span class="n">scholars_mate</span><span class="p">,</span> <span class="m">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 2... Nc6 3. Qh5 Nf6 ( 3... g6 4. Qf3 Nf6 ) 4. Qxf7#</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Exportar o PGN depois de um movimento</span>
</span></span><span class="line"><span class="cl"><span class="nf">pgn</span><span class="p">(</span><span class="nf">back</span><span class="p">(</span><span class="n">scholars_mate</span><span class="p">,</span> <span class="m">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;2... Nc6 3. Qh5 Nf6 ( 3... g6 4. Qf3 Nf6 ) 4. Qxf7#&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Imagem do tabuleiro atual</span>
</span></span><span class="line"><span class="cl"><span class="nf">plot</span><span class="p">(</span><span class="n">scholars_mate</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/chess/board.webp"/>
</figure>
<h2 id="motivação">Motivação</h2>
<p>O python-chess serviu como inspiração (e base) para o <code>{chess}</code>. Enquanto a
versão original (e o <a href="https://github.com/jbkunst/rchess"><code>{rchess}</code></a>, por sinal)
trabalha genericamente com &ldquo;geração de jogadas, validação de jogadas&rdquo; (com classes
poderosas e sintaxe orientada a objeto), o <code>{chess}</code> é focado em facilitar a
criação e exploração de árvores PGN.</p>
<p>Ao limitar o escopo da API, eu acredito que o pacote fica mais intuitivo para
pessoas que só querem um jeito rápido de criar análises de jogos compartilháveis
ou facilmente explorar os jogos dos outros sem precisar depender de um software
visual.</p>
<p>O primeiro uso do <code>{chess}</code> foi me ajudando a estudar o <em>My 60 Memorable Games</em>
do Bobby Fischer. Depois de um <a href="https://github.com/clente/chess/blob/master/data-raw/m60mg.R">parsing</a>
muito difícil, eu consegui converter o livro todo para PGN e <a href="https://lichess.org/study/4zOTO2ki">disponibilizá-lo no
lichess</a>, mas eu ainda achava que a interface
não era boa o suficiente&hellip;</p>
]]></content:encoded>
    </item>
    <item>
      <title>if_else() vs. ifelse()</title>
      <link>https://lente.dev/posts/if_else-ifelse/</link>
      <pubDate>Fri, 11 Sep 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/if_else-ifelse/</guid>
      <description>Por que às vezes recebemos warnings no if_else(), mas não no ifelse()? Uma investigação revela que o problema pode não estar onde imaginamos&amp;hellip;</description>
      <content:encoded><![CDATA[<p>Em uma <a href="https://discourse.curso-r.com/t/warnings-no-if-else-case-when-mas-nao-no-ifelse/529">dicussão</a> recente no <a href="https://discourse.curso-r.com/">fórum da Curso-R</a>, o <a href="https://github.com/jtrecenti">Julio</a> perguntou por que às vezes recebemos alertas no <code>dplyr::if_else()</code>, mas não no <code>ifelse()</code>. O exemplo apresentado foi o seguinte:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">tidyverse</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">funcao_chata</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">any</span><span class="p">(</span><span class="n">x</span> <span class="o">&gt;</span> <span class="m">10</span><span class="p">))</span> <span class="nf">warning</span><span class="p">(</span><span class="s">&#34;não gosto de vc&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="m">1</span> <span class="o">/</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># usando if_else(), com warnings</span>
</span></span><span class="line"><span class="cl"><span class="n">resultado</span> <span class="o">&lt;-</span> <span class="n">mtcars</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mutate</span><span class="p">(</span><span class="n">res</span> <span class="o">=</span> <span class="nf">if_else</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpg</span> <span class="o">&lt;</span> <span class="m">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">funcao_chata</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpg</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning: Problem with `mutate()` input `res`.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ℹ não gosto de vc</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ℹ Input `res` is `if_else(mpg &lt; 10, funcao_chata(mpg), mpg)`.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning in funcao_chata(mpg): não gosto de vc</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># usando case_when(), com warnings</span>
</span></span><span class="line"><span class="cl"><span class="n">resultado</span> <span class="o">&lt;-</span> <span class="n">mtcars</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mutate</span><span class="p">(</span><span class="n">res</span> <span class="o">=</span> <span class="nf">case_when</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpg</span> <span class="o">&lt;</span> <span class="m">10</span> <span class="o">~</span> <span class="nf">funcao_chata</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="kc">TRUE</span> <span class="o">~</span> <span class="n">mpg</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning: Problem with `mutate()` input `res`.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ℹ não gosto de vc</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ℹ Input `res` is `case_when(mpg &lt; 10 ~ funcao_chata(mpg), TRUE ~ mpg^2)`.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning: não gosto de vc</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># usando ifelse(), sem warnings</span>
</span></span><span class="line"><span class="cl"><span class="n">resultado</span> <span class="o">&lt;-</span> <span class="n">mtcars</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mutate</span><span class="p">(</span><span class="n">res</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpg</span> <span class="o">&lt;</span> <span class="m">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">funcao_chata</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpg</span>
</span></span><span class="line"><span class="cl">  <span class="p">))</span></span></span></code></pre></div><p>A pergunta é muito pertinente e já foi feita <a href="https://stackoverflow.com/questions/60079566/vectorized-if-else-or-case-when-which-doesnt-eagerly-evaluate-its-potential-out">outras vezes</a>, mas, para ficar bem claro, esse comportamento é <em>proposital</em>. Veja o que o Hadley fala na <a href="https://vctrs.r-lib.org/articles/stability.html#ifelse-">vignette</a> sobre estabilidade do <code>{vectrs}</code>:</p>
<blockquote>
<p>Unlike <code>ifelse()</code> this implies that <code>if_else()</code> must always evaluate both <code>yes</code> and <code>no</code> in order to figure out the correct type. I think this is consistent with <code>&amp;&amp;</code> (scalar operation, short circuits) and <code>&amp;</code> (vectorised, evaluates both sides).</p>
</blockquote>
<p>Como fica claro pelas próprias palavras do Hadley, esse tipo de comportamento tem precedentes no R, mas para entender exatamente o que ele quer dizer vamos ter que aprender sobre alguns conceitos de linguagens de programação. Infelizmente vou aproveitar a pergunta para fazer o meu diploma valer alguma coisa&hellip;</p>
<h3 id="execução-especulativa">Execução especulativa</h3>
<p><a href="https://en.wikipedia.org/wiki/Speculative_execution">Execução especulativa</a> uma técnica de otimização na qual um programa executa uma tarefa que talvez não seja necessária. Isso pode ser útil por uma série de razões apesar de parecer um desperdício! Se o seu computador consegue processar comandos em paralelo, ele pode executar a condição do <code>if</code>, o resultado caso ela seja <code>TRUE</code> e o resultado caso ela seja <code>FALSE</code> <em>ao mesmo tempo</em>, permitindo uma resposta até 2x mais rápida.</p>
<p>Essa técnica é tão comum que aqueles famosos bugs de 2018 (<a href="https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)">Spectre</a> e <a href="https://en.wikipedia.org/wiki/Meltdown_(security_vulnerability)">Meltdown</a>) acontecem principalmente por causa dela.</p>
<p>Voltando para o <code>if_else()</code>, a sua implementação de execução especulativa é diferentemente da de outras linguagens que tentam &ldquo;adivinhar&rdquo; se o <code>if</code> vai retornar <code>TRUE</code> ou <code>FALSE</code>: ele usa <a href="https://en.wikipedia.org/wiki/Eager_evaluation">avaliação ansiosa</a>, ou seja, ele sempre executa os dois ramos do condicional independentemente do resultado do <code>if</code>. A motivação disso é bem diferente de &ldquo;otimizar&rdquo; a computação (como vimos no exemplo anterior), mas sim <em>garantir que ambos os lados da resposta vão ter o mesmo comprimento e o mesmo tipo</em>.</p>
<p>Veja o <a href="https://github.com/tidyverse/dplyr/blob/master/R/if_else.R#L30">código</a> do <code>if_else()</code> e perceba que nele não existe nenhum <code>if</code> ou <code>else</code>, ou seja, ambos os ramos do condicional necessariamente vão ser executados:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">if_else</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">condition</span><span class="p">,</span> <span class="n">true</span><span class="p">,</span> <span class="n">false</span><span class="p">,</span> <span class="n">missing</span> <span class="o">=</span> <span class="kc">NULL</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">is.logical</span><span class="p">(</span><span class="n">condition</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">bad_args</span><span class="p">(</span><span class="s">&#34;condition&#34;</span><span class="p">,</span> <span class="s">&#34;must be a logical vector.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="n">true</span><span class="nf">[rep</span><span class="p">(</span><span class="kc">NA_integer_</span><span class="p">,</span> <span class="nf">length</span><span class="p">(</span><span class="n">condition</span><span class="p">))</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">replace_with</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span><span class="p">,</span> <span class="n">condition</span><span class="p">,</span> <span class="n">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fmt_args</span><span class="p">(</span><span class="o">~</span> <span class="n">true</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">glue</span><span class="p">(</span><span class="s">&#34;length of {fmt_args(~condition)}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">replace_with</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span><span class="p">,</span> <span class="o">!</span><span class="n">condition</span><span class="p">,</span> <span class="n">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fmt_args</span><span class="p">(</span><span class="o">~</span> <span class="n">false</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">glue</span><span class="p">(</span><span class="s">&#34;length of {fmt_args(~condition)}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">replace_with</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span><span class="p">,</span> <span class="nf">is.na</span><span class="p">(</span><span class="n">condition</span><span class="p">),</span> <span class="n">missing</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fmt_args</span><span class="p">(</span><span class="o">~</span> <span class="n">missing</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nf">glue</span><span class="p">(</span><span class="s">&#34;length of {fmt_args(~condition)}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">out</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="avaliação-de-curto-circuito">Avaliação de curto-circuito</h3>
<p>O conceito de <a href="https://en.wikipedia.org/wiki/Short-circuit_evaluation">avaliação de curto-circuito</a> é mais simples e foi citado diretamente pelo Hadley. Ele basicamente quer dizer que, em uma operação booleana, o segundo argumento somente será executado se o valor do primeiro não for suficiente para determinar o valor da expressão (por exemplo, se temos <code>A &amp;&amp; B</code> e <code>A</code> for <code>FALSE</code>, não precisamos saber o valor de <code>B</code> para saber que a resposta da expressão é <code>FALSE</code>).</p>
<p>Armados desse conhecimento, podemos entender finalmente a frase do Hadley: &ldquo;I think this is consistent with <code>&amp;&amp;</code> (scalar operation, short circuits) and <code>&amp;</code> (vectorised, evaluates both sides)&rdquo;. A implementação do <code>if_else()</code> foi feita para ser consistente com o operador <code>&amp;</code>, ou seja, vetorizada e com avaliação especulativa (ansiosa), enquanto um <code>if-else</code> comum é consistente com o <code>&amp;&amp;</code>, a saber, escalar e com avaliação de curto-circuito.</p>
<p>Agora vamos ver alguns exemplos para tentar entender como cada um desses operadores se comporta:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Função que retorna TRUE</span>
</span></span><span class="line"><span class="cl"><span class="n">f</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">warning</span><span class="p">(</span><span class="s">&#34;ANSIOSO&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kc">TRUE</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Preguiçoso (só escalares)</span>
</span></span><span class="line"><span class="cl"><span class="kr">if</span> <span class="p">(</span><span class="kc">TRUE</span><span class="p">)</span> <span class="kc">TRUE</span> <span class="kr">else</span> <span class="nf">f</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] TRUE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ansioso (funciona para vetores)</span>
</span></span><span class="line"><span class="cl"><span class="n">dplyr</span><span class="o">::</span><span class="nf">if_else</span><span class="p">(</span><span class="kc">TRUE</span><span class="p">,</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="nf">f</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning in f(): ANSIOSO</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] TRUE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Com curto-circuito (só escalares)</span>
</span></span><span class="line"><span class="cl"><span class="kc">FALSE</span> <span class="o">&amp;&amp;</span> <span class="nf">f</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] FALSE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Sem curto-circuito (fuciona para vetores)</span>
</span></span><span class="line"><span class="cl"><span class="kc">FALSE</span> <span class="o">&amp;</span> <span class="nf">f</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Warning in f(): ANSIOSO</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] FALSE</span></span></span></code></pre></div><p>Acho que com esses códigos fica claro que, na verdade, o <code>ifelse()</code> é a <em>exceção</em> e não a regra! Note que aqui eu usei sempre entradas escalares (comprimento 1) por questão didática, mas estão marcados os operadores que podem receber vetores.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Preguiçoso (funciona para vetores)</span>
</span></span><span class="line"><span class="cl"><span class="nf">ifelse</span><span class="p">(</span><span class="kc">TRUE</span><span class="p">,</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="nf">f</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] TRUE</span></span></span></code></pre></div><p>Conclui-se que, no que diz respeito à pergunta, não existe um jeito óbvio de fazer o <code>if_else()</code> e o <code>case_when()</code> trabalharem com execução preguiçosa sem mudar fundamentalmente o comportamento (e a lógica por trás) dessas funções.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Strings, datas e listas</title>
      <link></link>
      <pubDate>Sat, 15 Aug 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Abandonando o master</title>
      <link>https://lente.dev/posts/main-branch/</link>
      <pubDate>Mon, 27 Jul 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/main-branch/</guid>
      <description>O GitHub está abandonado o termo &amp;lsquo;master&amp;rsquo;. Veja como se adiantar e adotar o &amp;lsquo;main&amp;rsquo; a partir de já.</description>
      <content:encoded><![CDATA[<p>A terminologia <em>master/slave</em> (mestre/escravo) existe há muitas décadas na computação e parece ter <a href="https://en.wikipedia.org/wiki/Master/slave_(technology)">migrado</a> para a indústria da tecnologia já no início do século XX. Esses conceitos normalmente estão associados a um modelo de comunicação assimétrico no qual um processo ou aparelho (o &ldquo;mestre&rdquo;) controla outros processos ou aparelhos (os &ldquo;escravos&rdquo;). Não é necessário dizer que os termos vêm sendo contestados há anos devido à evidente conotação racista, mas o debate ganhou nova vida após os protestos do Black Lives Matter em 2020.</p>
<p>Várias linguagens de programação já abandonaram essa terminologia. Em 2018, no caso em que possivelmente houve maior repercussão até hoje, o Python <a href="https://www.vice.com/en_us/article/8x7akv/masterslave-terminology-was-removed-from-python-programming-language">abandonou</a> a palavra <em>master</em> por <em>parent process</em> (processo pai) e a palavra <em>slave</em> por <em>worker</em> (trabalhador) ou <em>helper</em> (ajudante) após um <a href="https://bugs.python.org/issue34605">debate</a> acalorado.</p>
<p>Enquanto isso, já em 2014, o Django passou a adotar a terminologia <em>primary/replica</em> (primário/réplica) e foi seguido pelo Drupal. Em 2017, o Internet Systems Consortium optou por <em>primary/secondary</em> (primário/secundário). Como se pode ver, não faltam alternativas para uma referência à escravidão.</p>
<p>Enfim, este ano foi a vez do GitHub. Desde sua criação, a plataforma de controle de versão tem utilizado o termo <em>master</em> para tratar do <em>branch</em> principal de um repositório e, apesar de nem existir uma analogia para algo como um <em>slave branch</em>, a palavra continua até hoje. Antes tarde do que nunca, a empresa <a href="https://www.vice.com/en_us/article/k7qbyv/github-to-remove-masterslave-terminology-from-its-platform">anunciou</a> que vai fazer uma transição em breve para o termo <em>main</em> (principal) e aposentar seu antecessor.</p>
<p>Justamente por pretender ser uma comunidade inclusiva e aberta, alguns programadores de R já começaram a transferir seus repositórios do GitHub para o novo modelo. Em seu blog, <a href="https://stevenmortimer.com/5-steps-to-change-github-default-branch-from-master-to-main/">Steven Mortimer</a> forneceu o passo-a-passo para fazermos o mesmo. Os comandos são bastante simples e estão listados abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1"># Passo 1</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Crie o branch &#39;main&#39; localmente trazendo o histórico do &#39;master&#39;</span>
</span></span><span class="line"><span class="cl">git branch -m master main
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Passo 2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Faça o push do novo branch para o GitHub</span>
</span></span><span class="line"><span class="cl">git push -u origin main
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Passo 3</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Substitua o HEAD do &#39;master&#39; para o &#39;main&#39;</span>
</span></span><span class="line"><span class="cl">git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Passo 4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Troque o branch padrão no GitHub para o &#39;main&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://docs.github.com/pt/github/administering-a-repository/setting-the-default-branch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Passo 5</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Delete o &#39;master&#39;</span>
</span></span><span class="line"><span class="cl">git push origin --delete master</span></span></code></pre></div><p>Note apenas que o Passo 4 deve ser realizado diretamente no GitHub de acordo com a <a href="https://docs.github.com/pt/github/administering-a-repository/setting-the-default-branch">documentação</a> (disponível em português).</p>
<p>Caso você queira que o processo seja completamente automatizado, existe um <a href="https://eyqs.ca/tools/rename/">aplicativo web</a> que faz tudo para você. Para saber mais sobre os esforços do próprio GitHub, acesse <a href="https://github.com/github/renaming">a página</a> na qual estão sendo discutidas as mudanças.</p>
]]></content:encoded>
    </item>
    <item>
      <title>R em produção</title>
      <link></link>
      <pubDate>Sat, 20 Jun 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Web scraping em R pt. 2</title>
      <link></link>
      <pubDate>Sat, 25 Apr 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Abaixo ao rvest!</title>
      <link>https://lente.dev/posts/rvest-xml2/</link>
      <pubDate>Thu, 09 Apr 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/rvest-xml2/</guid>
      <description>O rvest já não é mais o melhor pacote para web scraping. Está na hora de voltar para o xml2!</description>
      <content:encoded><![CDATA[<p>Se você já trabalhou com
<a href="https://www.curso-r.com/material/webscraping/">web scraping</a>, então
provavelmente você já ouviu falar de três pacotes: <code>httr</code>, <code>xml2</code> e <code>rvest</code>.
Talvez você não conheça ainda o <code>xml2</code>, mas o <code>rvest</code> foi por muito tempo o
divulgado como o principal pacote do R para raspagem de dados. A realidade,
entretanto, é que seu reinado acabou.</p>
<p>Como este post é voltado para pessoas que já têm um pouco de experiência com web
scraping em R, não vou me alongar em explicar o que cada função do <code>rvest</code> faz.
Meu objetivo aqui é apresentar para o leitor as principais alternativas do
<code>xml2</code> (e do <code>httr</code>) para o <code>rvest</code>.</p>
<h2 id="o-fim-de-uma-era">O fim de uma era</h2>
<p>Acredite, eu digo isso com muito pesar, mas o <code>rvest</code> está morto. Ele pode ter
sido muito útil em um passado distante, mas hoje em dia a nossa melhor opção
para a raspagem de dados é o bom e velho <code>xml2</code>.</p>
<p>A realidade é que o <code>rvest</code> nunca passou de um wrapper em torno do <code>xml2</code> e do
<code>httr</code>; esta é inclusive a sua descrição oficial: <em>Wrappers em torno dos pacotes
&lsquo;xml2&rsquo; e &lsquo;httr&rsquo; para facilitar o download e a manipulação de HTML e XML</em>. Mas se
o <code>rvest</code> está uma camada acima do <code>xml2</code>, então por que abandoná-lo por essa
alternativa mais &ldquo;rústica&rdquo;?</p>
<p>O grande problema do <code>rvest</code> é que ele foi majoritariamente abandonado. É verdade
que ele teve três novas atualizações em 2019, mas estas não passaram de pequenos
ajustes. O último lançamento relevante do <code>rvest</code> (a versão 0.3.0) foi em 2015,
praticamente dois séculos atrás em anos da Internet.</p>
<p>Nestes últimos 4 anos e pouco, o <code>xml2</code> continuou sendo atualizado e acabou se
tornando tão simples de usar quanto o seu aparente sucessor. Por isso, na minha
opinião, hoje em dia é mais fácil aprender web scraping direto com o original.</p>
<h2 id="pequenas-diferenças">Pequenas diferenças</h2>
<p>A principal diferença entre os dois é que o <code>xml2</code> trabalha com XPath e não
seletores CSS. Na minha opinião, o XPath é muito mais poderoso que os seletores,
mas a verdade é que trabalhar com ambos é praticamente igual! Quando você
estiver no seu navegador explorando a estrutura HTML de uma página a ser
raspada, basta clicar com o botão direito e copiar um ao invés do outro.
Inclusive existem até alguns
<a href="https://ghostinspector.com/docs/css-xpath-conversion/">guias</a> de conversão de
um para o outro; o XPath é naturalmente mais verborrágico, mas ele compensa com
algumas capacidades a mais.</p>
<p>Depois que você tiver se acostumado com o XPath, basta entender qual é o nome
da nova função a utilizar.</p>
<table>
<thead>
<tr>
<th style="text-align:left"><code>rvest</code></th>
<th style="text-align:left"><code>xml2</code>/<code>httr</code></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>rvest::html_session()</code></td>
<td style="text-align:left">Desnecessário com o <code>httr</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::follow_link()</code></td>
<td style="text-align:left"><code>httr::GET()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::read_html()</code></td>
<td style="text-align:left"><code>xml2::read_html()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_nodes()</code></td>
<td style="text-align:left"><code>xml2::xml_find_all()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_node()</code></td>
<td style="text-align:left"><code>xml2::xml_find_first()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_text()</code></td>
<td style="text-align:left"><code>xml2::xml_text()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_table()</code></td>
<td style="text-align:left"></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_attr()</code></td>
<td style="text-align:left"><code>xml2::xml_attr()</code></td>
</tr>
<tr>
<td style="text-align:left"><code>rvest::html_children()</code></td>
<td style="text-align:left"><code>xml2::xml_children()</code></td>
</tr>
<tr>
<td style="text-align:left"></td>
<td style="text-align:left"><code>xml2::xml_parents()</code></td>
</tr>
<tr>
<td style="text-align:left"></td>
<td style="text-align:left"><code>xml2::xml_contents()</code></td>
</tr>
<tr>
<td style="text-align:left"></td>
<td style="text-align:left"><code>xml2::xml_siblings()</code></td>
</tr>
</tbody>
</table>
<p>Como fica claro acima, o <code>xml2</code> possui praticamente todas as funções que o
<code>rvest</code> possui e mais algumas. A grande vantagem de usar o primeiro é precisar
de uma dependência a menos: o <code>rvest</code> já importa o <code>xml2</code>, então porque não
fazer tudo direto em <code>xml2</code>?</p>
<p>A única grande ausência do <code>xml2</code> é o <code>html_table()</code>, mas isso pode ser
facilmente corrigido com o código abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#&#39; Parse an html table into a data frame</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @param x A node, node set or document.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @param header Use first row as header? If NA, will use first row if it consists of th tags.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @param trim Remove leading and trailing whitespace within each cell?</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @param fill If TRUE, automatically fill rows with fewer than the maximum number of columns with NAs.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @param dec The character used as decimal mark.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&#39; @export</span>
</span></span><span class="line"><span class="cl"><span class="n">xml_table</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">header</span> <span class="o">=</span> <span class="kc">NA</span><span class="p">,</span> <span class="n">trim</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="n">fill</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">,</span> <span class="n">dec</span> <span class="o">=</span> <span class="s">&#34;.&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="s">&#34;xml_nodeset&#34;</span> <span class="o">%in%</span> <span class="nf">class</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">return</span><span class="p">(</span><span class="nf">lapply</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">xml_table</span><span class="p">,</span> <span class="n">header</span> <span class="o">=</span> <span class="n">header</span><span class="p">,</span> <span class="n">trim</span> <span class="o">=</span> <span class="n">trim</span><span class="p">,</span> <span class="n">fill</span> <span class="o">=</span> <span class="n">fill</span><span class="p">,</span> <span class="n">dec</span> <span class="o">=</span> <span class="n">dec</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nf">stopifnot</span><span class="p">(</span><span class="n">xml2</span><span class="o">::</span><span class="nf">xml_name</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;table&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">rows</span> <span class="o">&lt;-</span> <span class="n">xml2</span><span class="o">::</span><span class="nf">xml_find_all</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="s">&#34;.//tr&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">n</span> <span class="o">&lt;-</span> <span class="nf">length</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">cells</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">rows</span><span class="p">,</span> <span class="n">xml2</span><span class="o">::</span><span class="n">xml_find_all</span><span class="p">,</span> <span class="n">xpath</span> <span class="o">=</span> <span class="s">&#34;.//td|.//th&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">ncols</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">cells</span><span class="p">,</span> <span class="n">xml2</span><span class="o">::</span><span class="n">xml_attr</span><span class="p">,</span> <span class="s">&#34;colspan&#34;</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s">&#34;1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">ncols</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">ncols</span><span class="p">,</span> <span class="n">as.integer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">nrows</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">cells</span><span class="p">,</span> <span class="n">xml2</span><span class="o">::</span><span class="n">xml_attr</span><span class="p">,</span> <span class="s">&#34;rowspan&#34;</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s">&#34;1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">nrows</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">nrows</span><span class="p">,</span> <span class="n">as.integer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">p</span> <span class="o">&lt;-</span> <span class="nf">unique</span><span class="p">(</span><span class="nf">vapply</span><span class="p">(</span><span class="n">ncols</span><span class="p">,</span> <span class="n">sum</span><span class="p">,</span> <span class="nf">integer</span><span class="p">(</span><span class="m">1</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="n">maxp</span> <span class="o">&lt;-</span> <span class="nf">max</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">1</span> <span class="o">&amp;</span> <span class="n">maxp</span> <span class="o">*</span> <span class="n">n</span> <span class="o">!=</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">unlist</span><span class="p">(</span><span class="n">nrows</span><span class="p">))</span> <span class="o">&amp;</span> <span class="n">maxp</span> <span class="o">*</span> <span class="n">n</span> <span class="o">!=</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">unlist</span><span class="p">(</span><span class="n">ncols</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="n">fill</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nf">stop</span><span class="p">(</span><span class="s">&#34;Table has inconsistent number of columns. &#34;</span><span class="p">,</span> <span class="s">&#34;Do you want fill = TRUE?&#34;</span><span class="p">,</span> <span class="n">call.</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">values</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="n">cells</span><span class="p">,</span> <span class="n">xml2</span><span class="o">::</span><span class="n">xml_text</span><span class="p">,</span> <span class="n">trim</span> <span class="o">=</span> <span class="n">trim</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">out</span> <span class="o">&lt;-</span> <span class="nf">matrix</span><span class="p">(</span><span class="kc">NA_character_</span><span class="p">,</span> <span class="n">nrow</span> <span class="o">=</span> <span class="n">n</span><span class="p">,</span> <span class="n">ncol</span> <span class="o">=</span> <span class="n">maxp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">row</span> <span class="o">&lt;-</span> <span class="n">values[[i]]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ncol</span> <span class="o">&lt;-</span> <span class="n">ncols[[i]]</span>
</span></span><span class="line"><span class="cl">    <span class="n">col</span> <span class="o">&lt;-</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">ncol</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">out[i</span><span class="p">,</span> <span class="n">col</span><span class="o">:</span><span class="p">(</span><span class="n">col</span> <span class="o">+</span> <span class="n">ncol[j]</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="n">row[[j]]</span>
</span></span><span class="line"><span class="cl">      <span class="n">col</span> <span class="o">&lt;-</span> <span class="n">col</span> <span class="o">+</span> <span class="n">ncol[j]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">maxp</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">for</span> <span class="p">(</span><span class="n">j</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">rowspan</span> <span class="o">&lt;-</span> <span class="n">nrows[[j]][i]</span>
</span></span><span class="line"><span class="cl">      <span class="n">colspan</span> <span class="o">&lt;-</span> <span class="n">ncols[[j]][i]</span>
</span></span><span class="line"><span class="cl">      <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">rowspan</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">rowspan</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">colspan</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">colspan</span> <span class="o">&gt;</span> <span class="m">1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">nrows[[j]]</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">utils</span><span class="o">::</span><span class="nf">head</span><span class="p">(</span><span class="n">nrows[[j]]</span><span class="p">,</span> <span class="n">i</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nf">rep</span><span class="p">(</span><span class="n">rowspan</span><span class="p">,</span> <span class="n">colspan</span> <span class="o">-</span> <span class="m">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">utils</span><span class="o">::</span><span class="nf">tail</span><span class="p">(</span><span class="n">nrows[[j]]</span><span class="p">,</span> <span class="nf">length</span><span class="p">(</span><span class="n">rowspan</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="n">rowspan</span> <span class="o">&lt;-</span> <span class="n">nrows[[j]][i]</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="kr">for</span> <span class="p">(</span><span class="n">k</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">rowspan</span> <span class="o">-</span> <span class="m">1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">l</span> <span class="o">&lt;-</span> <span class="n">utils</span><span class="o">::</span><span class="nf">head</span><span class="p">(</span><span class="n">out[j</span> <span class="o">+</span> <span class="n">k</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="n">r</span> <span class="o">&lt;-</span> <span class="n">utils</span><span class="o">::</span><span class="nf">tail</span><span class="p">(</span><span class="n">out[j</span> <span class="o">+</span> <span class="n">k</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span> <span class="n">maxp</span> <span class="o">-</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="n">out[j</span> <span class="o">+</span> <span class="n">k</span><span class="p">,</span> <span class="n">]</span> <span class="o">&lt;-</span> <span class="n">utils</span><span class="o">::</span><span class="nf">head</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">out[j</span><span class="p">,</span> <span class="n">i]</span><span class="p">,</span> <span class="n">r</span><span class="p">),</span> <span class="n">maxp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">header</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">header</span> <span class="o">&lt;-</span> <span class="nf">all</span><span class="p">(</span><span class="n">xml2</span><span class="o">::</span><span class="nf">xml_name</span><span class="p">(</span><span class="n">cells[[1]]</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;th&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="n">header</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">col_names</span> <span class="o">&lt;-</span> <span class="n">out[1</span><span class="p">,</span> <span class="p">,</span> <span class="n">drop</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">&lt;-</span> <span class="n">out[</span><span class="m">-1</span><span class="p">,</span> <span class="p">,</span> <span class="n">drop</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">col_names</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;X&#34;</span><span class="p">,</span> <span class="nf">seq_len</span><span class="p">(</span><span class="nf">ncol</span><span class="p">(</span><span class="n">out</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="nf">seq_len</span><span class="p">(</span><span class="n">maxp</span><span class="p">),</span> <span class="kr">function</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">utils</span><span class="o">::</span><span class="nf">type.convert</span><span class="p">(</span><span class="n">out[</span><span class="p">,</span> <span class="n">i]</span><span class="p">,</span> <span class="n">as.is</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="n">dec</span> <span class="o">=</span> <span class="n">dec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="nf">names</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="n">col_names</span>
</span></span><span class="line"><span class="cl">  <span class="nf">class</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="s">&#34;data.frame&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">attr</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="s">&#34;row.names&#34;</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="nf">.set_row_names</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">df[[1]]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="kr">if</span> <span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">col_names</span><span class="p">))</span> <span class="o">&lt;</span> <span class="nf">length</span><span class="p">(</span><span class="n">col_names</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">warning</span><span class="p">(</span><span class="s">&#34;At least two columns have the same name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">df</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Apesar de ser uma função bastante complicada, ela não passa de uma cópia do
código de <code>rvest::html_table()</code> utilizando apesar funções do <code>xml2</code>; com isso
você terá a sua própria implementação de <code>xml_table()</code>. E depois de uma ou duas
semanas, você já estará pronto para abandonar o <code>rvest</code> e voltar a usar o bom e
velho <code>xml2</code>!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Zen do R</title>
      <link></link>
      <pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>A poupança de Beethoven</title>
      <link>https://lente.dev/posts/poupanca-beethoven/</link>
      <pubDate>Thu, 20 Feb 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/poupanca-beethoven/</guid>
      <description>Explorando um pouco sobre currying e ggplot através da maluquice que são os juros compostos.</description>
      <content:encoded><![CDATA[<h2 id="uma-bela-herança">Uma Bela Herança</h2>
<p>O motivador da discussão deste post é meio estranho: em 17 de dezembro
de 2020 serão comemorados 250 anos desde o nascimento do grande
compositor alemão Ludwig van Beethoven. Não é incomum ver pessoas
abrindo poupanças para seus filhos logo quando nascem (para que eles
tenham um pé-de-meia quando crescerem) e isso me fez pensar como ficaria
uma poupança aberta para Beethoven 250 anos atrás…</p>
<p>Sendo assim, em pleno 2020, uma carta chega à casa do último herdeiro
vivo do músico, você, lhe dando acesso à recém-descoberta poupança do
seu tatara-tataravô. Como poderia existir uma poupança em 17 de dezembro
de 1770 ou como ela durou até hoje é um mistério, mas sabe-se que ela
foi aberta com o que atualmente seriam R$ 500,00.</p>
<h2 id="visualizando-a-poupança">Visualizando a Poupança</h2>
<p>Para saber quanto dinheiro há hoje na poupança, basta utilizar a fórmula de
juros compostos:


<math display="inline"><mrow><msub><mi>V</mi><mi>f</mi></msub><mo>=</mo><msub><mi>V</mi><mi>p</mi></msub><mo form="prefix" stretchy="false">(</mo><mn>1</mn><mo>+</mo><mi>j</mi><msup><mo form="postfix" stretchy="false">)</mo><mi>n</mi></msup></mrow></math>
. Aqui


<math display="inline"><msub><mi>V</mi><mi>f</mi></msub></math>
 é o valor final,


<math display="inline"><msub><mi>V</mi><mi>p</mi></msub></math>
 é o valor inicial,


<math display="inline"><mi>j</mi></math> é a taxa de juros e



<math display="inline"><mi>n</mi></math>
 é o número de períodos que o
dinheiro ficou guardado (número de anos se os juros forem anuais, número
de meses se os juros forem mensais, etc.).</p>
<p>Mas, muito mais do que simplesmente obter o valor final, é interessante
ver o crescimento dos fundos da poupança ao longo do tempo. Isso pode
ser feito com o pacote <code>ggplot2</code> facilmente: basta utilizar a fórmula
acima para cada um dos 250 anos e plotar esses pontos em um
<em>scatterplot</em>. Entretanto, temos uma opção ainda melhor.</p>
<p>Um recurso pouco conhecido do <code>ggplot2</code> é o <code>stat_function()</code>, capaz de
construir uma <strong>linha contínua</strong> no gráfico a partir de uma função que
recebe o valor de uma abscissa e retorna o valor da ordenada
correspondente. Ou seja, se tivermos uma função <code>f(x) = y</code>, podemos
passá-la como argumento para o <code>stat_function()</code> desenhá-la (com o nível
de resolução mais apropriado).</p>
<p>Sendo assim, precisamos transformar a função
<a href="https://pt.wikipedia.org/wiki/Aridade">ternária</a> <code>Vp*(1+j)**n</code> em uma
função que recebe apenas um argumento. Para isso devemos usar uma
técnica denominada <a href="https://pt.wikipedia.org/wiki/Currying">currying</a>,
que essencialmente “pré-preenche” argumentos de uma função; nesse caso,
vamos fixar o valor de <code>Vp</code> e <code>j</code> de modo que somente o <code>n</code> varie. A
função unária final, que podemos construir com <code>purrr::partial()</code>, nos
mostrará quanto tinha na poupança depois de <code>n</code> unidades de tempo (a
saber, anos).</p>
<p>O código final para a visualização é o seguinte:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">magrittr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Fórmula de juros compostos</span>
</span></span><span class="line"><span class="cl"><span class="n">juro_composto</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">Vp</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="n">Vp</span><span class="o">*</span><span class="p">(</span><span class="m">1</span><span class="o">+</span><span class="n">j</span><span class="p">)</span><span class="o">**</span><span class="n">n</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Gerar um gráfico de juros compostos</span>
</span></span><span class="line"><span class="cl"><span class="n">grafico_juros</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">Vp</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">SI</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Atalho para o ggplot (currying)</span>
</span></span><span class="line"><span class="cl">  <span class="n">juro_fixado</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">partial</span><span class="p">(</span><span class="n">juro_composto</span><span class="p">,</span> <span class="n">Vp</span> <span class="o">=</span> <span class="n">Vp</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Exibir eixos de forma abreviada</span>
</span></span><span class="line"><span class="cl">  <span class="n">scale_real</span> <span class="o">&lt;-</span> <span class="kr">if</span> <span class="p">(</span><span class="n">SI</span><span class="p">)</span> <span class="p">{</span> <span class="n">scales</span><span class="o">::</span><span class="nf">label_number_si</span><span class="p">(</span><span class="n">prefix</span> <span class="o">=</span> <span class="s">&#34;R$ &#34;</span><span class="p">)</span> <span class="p">}</span> <span class="kr">else</span> <span class="p">{</span> <span class="n">I</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Mostrar no gráfico</span>
</span></span><span class="line"><span class="cl">  <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">dplyr</span><span class="o">::</span><span class="nf">tibble</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="n">.)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">ggplot</span><span class="p">(</span><span class="n">ggplot2</span><span class="o">::</span><span class="nf">aes</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">stat_function</span><span class="p">(</span><span class="n">fun</span> <span class="o">=</span> <span class="n">juro_fixado</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">scale_y_continuous</span><span class="p">(</span><span class="n">labels</span> <span class="o">=</span> <span class="n">scale_real</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">xlab</span><span class="p">(</span><span class="s">&#34;Anos&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">ylab</span><span class="p">(</span><span class="s">&#34;Valor Final&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="n">ggplot2</span><span class="o">::</span><span class="nf">theme_minimal</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Agora vamos para os detalhes da poupança. Para desconsiderarmos a
inflação, digamos que a poupança começou com o que nos valores de hoje
seriam R$ 500,00; uma poupança rende, em média, módicos 6% ao ano,
então vamos usar isso como referência; por fim, o dinheiro ficou parado
lá por 250 anos. Quanto você acha que terá na conta agora em 2020?</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">grafico_juros</span><span class="p">(</span><span class="m">500</span><span class="p">,</span> <span class="m">0.06</span><span class="p">,</span> <span class="m">250</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/beethoven-savings/unnamed-chunk-2-1.webp"/>
</figure>
<p>Como é de se esperar, juros compostos são uma função exponencial. Depois
desses 250 anos, os R$ 500,00 se tornaram mais de R$ 1B. Nada mal para
uma mera poupança.</p>
<h2 id="bônus">Bônus</h2>
<p>Aproveitando que já temos todo o código pronto, podemos visualizar
outras séries exponenciais. Se colocássemos 1 centavo na poupança no ano
1 D.C., hoje em dia teríamos aproximadamente R$ 1.3e+49, ou mais
ou menos R$ 0,10 para cada átomo da Terra. Essa é a mágica dos juros
compostos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">grafico_juros</span><span class="p">(</span><span class="m">0.01</span><span class="p">,</span> <span class="m">0.06</span><span class="p">,</span> <span class="m">2020</span><span class="p">,</span> <span class="kc">FALSE</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/beethoven-savings/unnamed-chunk-3-1.webp"/>
</figure>
<p>Uma propriedade interessante de frases como “crescimento de 3%” é que
raramente notamos que essa porcentagem se acumula ano-a-ano. Um país
cujo PIB cresce 3% ao ano tem que <strong>dobrar</strong> a sua economia a cada 25
anos. Atualmente o PIB do Brasil é de R$ 7T, vejamos o gráfico de nossa
economia crescendo a 3% todo ano:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">grafico_juros</span><span class="p">(</span><span class="m">7e12</span><span class="p">,</span> <span class="m">0.03</span><span class="p">,</span> <span class="m">25</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/beethoven-savings/unnamed-chunk-4-1.webp"/>
</figure>
<p>Isso pode não impressionar muito, mas, se começarmos a falar em escalas
globais, a coisa muda de figura. Os EUA têm um PIB de US$ 17T, enquanto
a soma de todos os PIBs do mundo dá aproximadamente US$ 80T; se a
economia estadunidense crescesse a 3% pelos próximos 100 anos,
precisaríamos de mais de 4 PIBs mundiais para chegar perto desse novo
PIB dos EUA.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">grafico_juros</span><span class="p">(</span><span class="m">17e12</span><span class="p">,</span> <span class="m">0.03</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/beethoven-savings/unnamed-chunk-5-1.webp"/>
</figure>
<p>Uma coisa que não cresce exponencialmente, entretanto, é a quantidade de
recursos disponíveis na natureza…</p>
]]></content:encoded>
    </item>
    <item>
      <title>Camadas de fake news</title>
      <link>https://lente.dev/posts/fake-news/</link>
      <pubDate>Tue, 21 Jan 2020 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/fake-news/</guid>
      <description>Uma fake news dura de roer. Como um gráfico pode estar tecnicamente certo e ao mesmo tempo não ser correto.</description>
      <content:encoded><![CDATA[<h2 id="eu-tenho-um-problema">Eu Tenho um Problema</h2>
<p>Esse problema se chama <em>fake news</em>. Não importa a fonte, a inclinação
ideológica, o estilo ou o grau da mentira; eu preciso me segurar muito
para não passar a tarde toda desmascarando as notícias falsas
(antigamente conhecidas simplesmente como mentiras) que chegam no meu
WhatsApp diariamente. Eu não ligo tanto para análises mal feitas ou
mesmo tendenciosas (já que na minha opinião isso faz parte de viver em
sociedade), mas quando o conteúdo parece deliberadamente montado para
ludibriar o leitor eu perco o controle.</p>
<p>Normalmente eu ignoro a mensagem/foto/montagem e sigo com o meu dia, mas
há ocasiões raras em que o nível da mentira é grande o bastante e eu
estou com a agenda livre o suficiente, que corro para o computador
com o único objetivo de desmentir a <em>fake news</em>. Geralmente em menos de
meia hora já tenho uma resposta pronta com dados confiáveis, uma imagem
sem Photoshop ou simplesmente um link para um site de <em>fact-checking</em>.
Mas ontem aconteceu algo inédito: a mentira lutou contra mim.</p>
<h2 id="a-notícia">A “Notícia”</h2>
<p>A “notícia” falsa em questão é na verdade uma imagem. Uma imagem
alterada, por sinal.</p>
<figure><img src="https://lente.dev/posts/fake-news/photo_2020-01-21_12-37-31.webp"/>
</figure>
<p>Vamos por partes. Meu espanhol não é dos melhores, mas acho que qualquer
lusófono consegue compreender bem o que está sendo mostrado: o gráfico
representa a posição de dois países no ranking de PIB per capita. Além
disso, destacam-se o período de 1882 a 1950 (quando a Argentina nunca
ficou abaixo do 10º maior PIB per capita), o período entre 1895 e 1896
(quando a Argentina estava em 1º lugar) e o ranking atual dos nossos
vizinhos (59º lugar).</p>
<p>De acordo com o que me parece ser a <a href="https://twitter.com/rcas1/status/1068171172766994432">imagem
original</a>, nesta
versão da notícia ganhamos de brinde também uma pequena intervenção
“artística” na forma de duas figuras da política Argentina: <a href="https://pt.wikipedia.org/wiki/Juan_Bautista_Alberdi">Juan
Bautista Alberdi</a>
(um dos principais responsáveis pela primeira Constituição argentina) e
<a href="https://pt.wikipedia.org/wiki/Juan_Domingo_Per%C3%B3n">Juan Domingo
Perón</a> (três
vezes presidente da Argentina). O texto que acompanha a foto de Perón
nos “informa” sobre a <a href="https://pt.wikipedia.org/wiki/Constitui%C3%A7%C3%A3o_Argentina#A_Constitui%C3%A7%C3%A3o_de_53_e_a_hist%C3%B3ria_pol%C3%ADtica_argentina">Constituição
de 1949</a>,
quando o governo peronista reforma a Carta Magna e aparentemente dá
início à “justiça social”.</p>
<p>O que esta imagem parece estar sugerindo é que Perón é o grande culpado
pela queda da Argentina no ranking do PIB per capita. A comparação com a
Austrália (que evidentemente não teve nenhum governo peronista) reforça
essa ideia porque ela permaneceu aproximadamente na camada superior do
gráfico. Implicitamente, o leitor parece ser encorajado a equivaler PIB
per capita com desenvolvimento econômico ou qualidade de vida.</p>
<p>Mas, como dito anteriormente, esta imagem não é uma <em>fake news</em>
qualquer: para desmentí-la será necessário explorar algumas camadas da
narrativa sendo traçada.</p>
<h2 id="os-dados-não-mentem">Os Dados Não Mentem…</h2>
<p>Diferentemente da maior parte das <em>fake news</em>, esta possui uma fonte. Os
dados foram retirados do <a href="https://www.rug.nl/ggdc/historicaldevelopment/maddison/releases/maddison-project-database-2018">Maddison
Project</a>,
um projeto acadêmico da Universidade de Groningen cujo objetivo é
estimar o valor de certas estatísticas econômicas para o passado
longínquo (mais sobre isso em breve).</p>
<p>Sendo assim, acessei o site do projeto e coletei os dados. Eles não
passam de uma planilha Excel com um país por coluna e um ano por linha,
com cada célula contendo o PIB per capita daquele país naquele ano em
dólares constantes de 2011.</p>
<p>Usando o <code>ggplot2</code> podemos reproduzir a imagem com facilidade:</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-2-1.webp"/>
</figure>
<p>Quando vi o gráfico, fiquei boquiaberto. Uma imagem em baixa resolução,
com Photoshop mal feito, linguagem tendenciosa e veiculada via WhatsApp
parecia não estar errada. Analisando o ranking da Argentina em 2016, o
país de fato estava na 62ª posição e não na 59ª, mas isso está longe de
desqualificar um argumento.</p>
<h2 id="mas-podem-enganar">…Mas Podem Enganar</h2>
<p>Mesmo estando <strong>tecnicamente</strong> certo, um gráfico não necessariamente
está correto. A próxima visualização que fiz pretendia explorar não o ranking
dos países, mas os seus PIBs per capita diretamente; isso é relevante
porque a suposta alegação do gráfico diz respeito à economia da
Argentina e não sobre ela em relação às de todos os outros países.</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-3-1.webp"/>
</figure>
<p>O que me chamou a atenção no gráfico acima foi que os PIBs per capita da
Argentina e da Austrália parecem estar se descolando consistentemente
desde 1905. Por que então o descolamento dos rankings só ocorre após
1950?</p>
<h2 id="contexto-importa">Contexto Importa…</h2>
<p>Depois de mexer mais no gráfico dos valores, notei que a grande maioria
dos países da tabela não tinham nenhum dado para antes de 1950. Isso me
fez procurar outras fontes para dados do PIB, mas não encontrei nada que
contemplasse um período tão grande quanto o do projeto Maddison. Sendo
assim, fui saber mais sobre o conceito de Produto Interno Bruto.</p>
<p>Em primeiro lugar, descobri que a <a href="https://en.wikipedia.org/wiki/Gross_domestic_product">definição
moderna</a> de PIB só
existe desde 1934 e que ele só começou a ser utilizado para medir a
economia dos países a partir de 1944.</p>
<p>E agora entra em jogo o que de fato é o projeto Maddison. Já comentei
que ele estima alguns índices socioeconômicos para o passado, mas não
falei sobre um detalhe vital que só descobri depois: o projeto estima
esses dados somente para um conjunto limitado de países! Ou seja, antes
de meados da década de 1950, só temos acesso à informação de um grupo
seleto de nações.</p>
<p>Voltando para a base, percebi que isso explicava a quantidade de países
com linhas vazias antes de 1950, pois apenas 28 nações possuíam
estimativas para o PIB per capita a desde 1875. É muito diferente dizer
que a Argentina tinha o maior PIB per capita do mundo em 1895 e dizer
que ela tinha o maior PIB per capita (estimado) entre 28 países
selecionados. Abaixo é possível ver o ranking até 2016 se filtrarmos
apenas os 28 países iniciais:</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-4-1.webp"/>
</figure>
<p>Fiz questão de manter a escala deste gráfico igual à do anterior porque
assim fica fácil de ver o problema com a visualização da “notícia”. De
fato a Argentina perdeu posições no ranking, isso é indiscutível, mas é
muito diferente perder algo em torno de 10 posições em 50 anos e perder
50 posições no mesmo período.</p>
<p>Para entender ainda melhor o que a imagem original está escondendo,
basta exibir no gráfico os dados de <strong>todos</strong> os países contemplados
pela base.</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-5-1.webp"/>
</figure>
<p>Note como a quantidade de países presentes na tabela cresce
significativamente depois do início da década de 1950 dado que a métrica
foi colocada em vigor apenas 6 anos antes. Sendo assim, é de se esperar
que a Argentina e até a Austrália percam posições no ranking. No fundo,
estamos visualizando uma base para antes de 1950 (as estimativas do
projeto Maddison) e uma para depois (as estatísticas reais coletadas
pela comunidade internacional).</p>
<p>Mais interessante ainda do que tentar visualizar todos os países em um
mesmo gráfico, é possível utilizar a função <code>dplyr::percent_rank()</code> que,
ao invés de atribuir números naturais como ranking, retorna o ranking
dividido pelo total de elementos na comparação.</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-6-1.webp"/>
</figure>
<p>Aqui fica claro que, mesmo depois de piorar muito no ranking do PIB per
capita, a Argentina ainda não está tão ruim quanto estava no início dos
anos 1880 (em relação a todos os países disponíveis para cada ano).
Conclusão muito diferente da sugerida pela imagem original.</p>
<h2 id="e-história-também">…E História Também</h2>
<p>A última camada dessa <em>fake news</em> é um pouco mais sutil e não pode ser
identificada olhando somente para os dados. Na verdade, só fiquei
sabendo disso enquanto pesquisava mais sobre a história da Argentina na
Wikipédia.</p>
<p>Sem querer entrar na discussão “peronistas vs. antiperonistas”, mas
nossos vizinhos possuem uma herança muito forte dos três governos de
Perón e a sociedade é fortemente dividida entre aqueles que apoiam seu
legado e aqueles que o rejeitam (de forma similar ao nosso sentimento em
relação a Vargas, mas certamente mais relevante para a política
contemporânea).</p>
<p>A imagem é claramente montada para manchar o legado de Perón e, para
isso, destaca a data na qual ele reformou a Constituição argentina. A
adição das fotos e do texto posteriormente em Photoshop é o que mais faz
soar meu alarme de notícia falsa.</p>
<p>O que aprendi sobre a história argentina, entretanto, parece colocar em
cheque a ideia de que teria sido a Constituição peronista que derrubou a
Argentina no ranking dos PIBs per capita: Perón foi deposto por um golpe
militar em 1955 e no ano seguinte foi publicada uma nova Constituição que
anulava a anterior. A Constituição de 1956 declarava “vigente la
Constitución Nacional sancionada en 1853, con las reformas de 1860, 1866
y 1898, y exclusión de la de 1949”.</p>
<p>Agora acho importante fazer uma visualização final, destacando a
vigência da Constituição que deu início à “justiça social”:</p>
<figure><img src="https://lente.dev/posts/fake-news/figure-gfm/unnamed-chunk-7-1.webp"/>
</figure>
<p>Sugiro que os autores da imagem original façam a mesma montagem com o
gráfico acima.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Shiny em produção</title>
      <link>https://lente.dev/posts/app-deploy/</link>
      <pubDate>Fri, 20 Sep 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/app-deploy/</guid>
      <description>Quando você for capaz de transformar um shiny app em pacote e em imagem de docker, só 20 minutos são necessários para fazer um deploy na nuvem.</description>
      <content:encoded><![CDATA[<p>Este é o último post na sequência que estou chamando de &ldquo;shiny em produção&rdquo;. Já
falamos sobre <a href="https://www.curso-r.com/blog/2019-07-16-golem/">como usar</a> o
pacote <code>golem</code> para facilitar o desenvolvimento de shiny apps, sobre
<a href="https://www.curso-r.com/blog/2019-08-27-app-pacote/">como transformar</a> eles em
pacotes e sobre
<a href="https://www.curso-r.com/blog/2019-09-04-app-docker/">como dockerizá-los</a> para
obter compatibilidade máxima.</p>
<p>E é justamente essa compatibilidade que nos permite fazer o deploy desses apps
na nuvem (mais especificamente no Google Cloud Platform) em menos de 20 minutos!
Como esse tutorial é muito visual, resolvemos fazer um vídeo para que tudo
ficasse mais claro:
<a href="https://www.youtube.com/watch?v=wLNQCQz5LEs">https://www.youtube.com/watch?v=wLNQCQz5LEs</a></p>
<p>Se você quiser acessar o repositório com o conteúdo, deixamos
<a href="https://github.com/curso-r/shinygcp">ele aberto</a> a todos. Por fim, segue abaixo
o código em Node utilizado para criar as Cloud Functions:</p>





<pre tabindex="0"><code>var http = require(&#39;http&#39;);
var Compute = require(&#39;@google-cloud/compute&#39;);
var compute = Compute();
exports.startInstance = function startInstance(req, res) {
  var zone = compute.zone(&#39;{SUA ZONA}&#39;);
  var vm = zone.vm(&#39;{SUA VM}&#39;);
  vm.start(function(err, operation, apiResponse) {
    console.log(&#39;instance start successfully&#39;);
  });
  res.status(200).send(&#39;Success start instance&#39;);
};

{
  &#34;name&#34;: &#34;sample-http&#34;,
  &#34;dependencies&#34;: {
    &#34;@google-cloud/compute&#34;: &#34;0.7.1&#34;},
  &#34;version&#34;: &#34;0.0.1&#34;
}

var http = require(&#39;http&#39;);
var Compute = require(&#39;@google-cloud/compute&#39;);
var compute = Compute();
exports.stopInstance = function stopInstance(req, res) {
  var zone = compute.zone(&#39;{SUA ZONA}&#39;);
  var vm = zone.vm(&#39;{SUA VM}&#39;);
  vm.stop(function(err, operation, apiResponse) {
    console.log(&#39;instance stop successfully&#39;);
  });
  res.status(200).send(&#39;Success stop instance&#39;);
};

{
  &#34;name&#34;: &#34;sample-http&#34;,
  &#34;dependencies&#34;: {
    &#34;@google-cloud/compute&#34;: &#34;0.7.1&#34;},
  &#34;version&#34;: &#34;0.0.1&#34;
}</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Shiny dockerizado</title>
      <link>https://lente.dev/posts/shiny-docker/</link>
      <pubDate>Tue, 03 Sep 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/shiny-docker/</guid>
      <description>Depois de transformar seu shiny app em pacote, agora só resta transformá-lo em uma imagem docker.</description>
      <content:encoded><![CDATA[<p>Recentemente, o <a href="https://github.com/jtrecenti">Julio</a> discutiu no
<a href="https://www.curso-r.com/blog/">blog da Curso-R</a>
<a href="https://www.curso-r.com/blog/2019-07-16-golem/">como usar</a> o pacote <code>golem</code>
para facilitar o desenvolvimento de shiny apps em forma de pacotes e
<a href="https://www.curso-r.com/blog/2019-08-27-app-pacote/">como transformar</a> esses
pacotes em &ldquo;executáveis&rdquo; de apenas uma linha. Nesse post eu vou continuar nessa
linha e falar sobre como pegar esse app de uma linha e embrulhá-lo em um
contêiner docker para que o seu deploy seja instantâneo.</p>
<h2 id="inst">Inst</h2>
<p>Essencialmente toda a magia da transformação de um app em um docker ocorre na
pasta <code>/inst</code>. Esse diretório, pouco utilizado no dia-a-dia, é útil quando
precisamos adicionar dados, templates ou qualquer conteúdo que pode ser
necessário em algum momento para o pacote e, portanto, devem ser facilmente
acessíveis.</p>
<p>Quando você transformar seu shiny app em pacote utilizando o tutorial do Julio,
você terá uma estrutura de diretórios padrão na raiz do seu app: pastas <code>/R</code>,
<code>/man</code> e assim por diante. Crie a pasta <code>/inst</code> e dentro dela <code>/app</code>; aqui é
onde seu app irá morar.</p>
<p>Em princípio, você só precisa de um arquivo <code>app.R</code> dentro de <code>/inst/app</code>
contendo aquela linha mágica que executa seu app todo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">shiny</span><span class="o">::</span><span class="nf">shinyApp</span><span class="p">(</span><span class="n">meuPacote</span><span class="o">:::</span><span class="nf">app_ui</span><span class="p">(),</span> <span class="n">meuPacote</span><span class="o">:::</span><span class="n">app_server</span><span class="p">)</span></span></span></code></pre></div><p>Se você estiver desenvolvendo um app mais complexo, talvez você precise
criar também uma pasta <code>/www</code> ou um
<a href="https://www.curso-r.com/blog/2019-07-19-auth0-pkg/">arquivo <code>_auth0.yml</code></a>, mas
o resumo da ópera é que você deve ser capaz de rodar <code>shiny::runApp()</code> nesta
pasta e ver o seu app funcionando perfeitamente. Durante o desenvolvimento, não
se esqueça de <strong>sempre reinstalar</strong> o seu pacote para que <code>meuPacote:::app_ui()</code>
e <code>meuPacote:::app_server</code> mantenham-se atualizados!</p>
<p>O último arquivo que você pode querer adicionar a <code>/inst/app</code> é a configuração
do seu servidor shiny. No meu caso, eu desenvolvo apps dockerizados para
subí-los em máquinas virtuais na nuvem que podem ser acessadas por qualquer um,
então preciso deixar clara qual porta deve ser utilizada pelo meu shiny. Como
minhas máquinas suportam o protocolo HTTP, meu <code>shiny-server.conf</code> é o seguinte:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">run_as shiny<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Log all Shiny output to files in this directory</span>
</span></span><span class="line"><span class="cl">log_dir /var/log/shiny-server<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Define a server that listens on port 80</span>
</span></span><span class="line"><span class="cl">server <span class="o">{</span>
</span></span><span class="line"><span class="cl">  listen 80<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Define a location at the base URL</span>
</span></span><span class="line"><span class="cl">  location / <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Host the directory of Shiny Apps stored in this directory</span>
</span></span><span class="line"><span class="cl">    site_dir /srv/shiny-server<span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># When a user visits the base URL rather than a particular application,</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># an index of the applications available in this directory will be shown.</span>
</span></span><span class="line"><span class="cl">    directory_index off<span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span></span></span></code></pre></div><p>Fazer com que o app seja ouvido na porta 80 permite que outra pessoas o acessem
sem precisar especificar uma porta no URL! Sendo assim, você pode disponibilizar
seu shiny app em <code>meuApp.dominio.com.br</code>.</p>
<h2 id="dockerfile">Dockerfile</h2>
<p>Agora que a sua pasta <code>/inst</code> está devidamente configurada, você precisa criar
um <code>Dockerfile</code> na raiz do seu app. Isso irá incomodar o <code>devtools::check()</code>,
mas basta adicionar o nome desse arquivo ao seu <code>.Rbuildignore</code> para que ele
seja ignorado durante a verificação.</p>
<p>Se todas as dependências do seu aplicativo estiverem devidamente organizadas no
<code>DESCRIPTION</code> e todas as suas bases internas estiverem propriamente exportadas
como documentado pelo Julio, então o seu <code>Dockerfile</code> deve ser parecido com o
seguinte:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> rocker/shiny-verse</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># Instalar bibliotecas para o tidyverse</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> apt-get update -qq <span class="o">&amp;&amp;</span> apt-get -y --no-install-recommends install <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  build-essential <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  libcurl4-gnutls-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  libxml2-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  libssl-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  r-cran-curl <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  r-cran-openssl <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  curl <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  gnupg1 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  r-cran-xml2<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># Instalar seu próprio app (e suas dependências)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">COPY</span> ./ /tmp/app/<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> R -e <span class="s2">&#34;remotes::install_local(&#39;/tmp/app/&#39;)&#34;</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># Copiar arquivos para o lugar certo</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 80/tcp</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> rm /srv/shiny-server/index.html<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">COPY</span> ./inst/app /srv/shiny-server/<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">COPY</span> ./inst/app/shiny-server.conf /etc/shiny-server/shiny-server.conf<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># Run</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">CMD</span> <span class="p">[</span><span class="s2">&#34;/usr/bin/shiny-server.sh&#34;</span><span class="p">]</span></span></span></code></pre></div><h2 id="deploy">Deploy</h2>
<p>Agora você já pode construir sua imagem docker e executá-la ou subí-la para
alguma máquina virtual. Para testar localmente o app, execute os comandos a
seguir no terminal e acesse <code>localhost:8080</code> no navegador:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">docker build -t meuApp pasta/para/meuApp
</span></span><span class="line"><span class="cl">docker run -p 8080:80 meuApp</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Transliteração em R</title>
      <link>https://lente.dev/posts/transliteracao/</link>
      <pubDate>Thu, 29 Aug 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/transliteracao/</guid>
      <description>Transliteração é uma das tarefas mais complicadas do tratamento de strings, mas o pacote stringi pode nos salvar.</description>
      <content:encoded><![CDATA[<p>Qual a relação entre as duas partes do título deste post? O que a remoção de
acentos de uma palavra em português pode ter a ver com o Ano Novo muçulmano? A
resposta é <strong>transliteração</strong>.</p>
<p>Transliteração é uma operação em strings pouco discutida, mas bastante
importante quando lidamos com idiomas que não o inglês. Ela implica na conversão
de texto de um sistema de escrita para outro, substituindo letras (ou
caracteres) de formas previsíveis, como, por exemplo, α → a ou æ → ae.</p>
<p>Em português é comum transliterarmos palavras sem mesmo saber o que isso
significa. Por exemplo, a palavra חנוכה (/ˡχanuka/) é normalmente escrita como
&ldquo;chanucá&rdquo; apesar de essa não ser uma correspondência da pronúncia hebraica para
os sons do português. Se quiséssemos uma transposição de pronúncia,
provavelmente escreveríamos &ldquo;ranucá&rdquo;, mas o mais correto é justamente
transliterar a palavra de modo a preservar uma certa correspondência entre as
letras do hebraico e as letras do português; sendo assim, a primeira letra é
transformada em um CH e não em um R. O mesmo ocorre com a romanização do japonês
e do mandarim, etc.</p>
<h2 id="letras-estrangeiras">Letras estrangeiras</h2>
<p>E qual a importância da transliteração no dia a dia? Em primeiro lugar, quando
lidamos com idiomas que apresentam caracteres distintos dos nossos, muitas vezes
as funções padrão do R não são capazes de tratar eles corretamente!</p>
<p>Vejamos por exemplo uma palavra do alemão e uma do holandês: &ldquo;groß&rdquo; e &ldquo;ijsvrij&rdquo;.
No alemão, a versão capitalizada do beta (ß) é SS, enquanto no holandês o
dígrafo IJ é na verdade uma letra só. Vejamos o que acontece se usamos as
funções padrões:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">toupper</span><span class="p">(</span><span class="s">&#34;groß&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;GROß&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">stringr</span><span class="o">::</span><span class="nf">str_to_title</span><span class="p">(</span><span class="s">&#34;ijsvrij&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;Ijsvrij&#34;</span></span></span></code></pre></div><p>Para corrigir esses problemas (o &ldquo;ß&rdquo; e o &ldquo;Ij&rdquo;), devemos utilizar funções do
pacote <code>stringi</code> que são capazes de transliterar as strings antes de aplicar
as outras transformações:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">stringi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">stri_trans_toupper</span><span class="p">(</span><span class="s">&#34;groß&#34;</span><span class="p">,</span> <span class="n">locale</span> <span class="o">=</span> <span class="s">&#34;de_DE&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;GROSS&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">stri_trans_totitle</span><span class="p">(</span><span class="s">&#34;ijsvrij&#34;</span><span class="p">,</span> <span class="n">locale</span> <span class="o">=</span> <span class="s">&#34;nl_NL&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;IJsvrij&#34;</span></span></span></code></pre></div><h2 id="acentos-do-português">Acentos do português</h2>
<p>O segundo uso da transliteração (e provavelmente mais comum no dia a dia) é a
remoção dos acentos do português. Muitas vezes recebemos arquivos e tabelas nos
quais a acentuação das palavras está quebrada ou incorreta, tornando necessária
a remoção dos diacríticos (acentos ortográficos + til + cedilha + trema + etc.)
de todas as strings.</p>
<p>Jamais devemos criar uma regex para realizar essa tarefa porque a chance de ela
não funcionar é muito grande! Suponha que esquecemos de um acento na regex, uma
forma capitalizada, ou mesmo a existência de palavras em outros idiomas no meio
de um texto em português. A solução para esse problema é, você adivinhou, a
transliteração.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">stri_trans_general</span><span class="p">(</span><span class="s">&#34;Stríng cõm müìtôs açëntòs&#34;</span><span class="p">,</span> <span class="s">&#34;Latin-ASCII&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;String com muitos acentos&#34;</span></span></span></code></pre></div><p>A função <code>stri_trans_general()</code> recebe dois argumentos: uma string e um
identificador de transformação. Neste caso e quando estivermos lidando com
português em geral, o que queremos é passar uma string no alfabeto latino (o
nosso alfabeto) para <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> (o conjunto
restrito de caracteres sem nenhum tipo de diacrítico) e, portanto, utilizamos o
ID <code>&quot;Latin-ASCII&quot;</code>.</p>
<h2 id="ano-novo-muçulmano">Ano Novo muçulmano</h2>
<figure><img src="https://lente.dev/posts/transliteration/corao.webp"/>
</figure>
<p>O terceiro e último uso da transliteração serve para quando lidamos com línguas
que apresentam ligaduras (duas ou mais letras unidas em um único glifo). O árabe
é o melhor exemplo disso porque grande parte da sua arte caligráfica envolve a
composição de diversas palavras em uma só figura [observe o círculo central da
imagem do Alcorão acima e repare como ele é preenchido por diversas palavras
entrelaçadas].</p>
<p>Como o Ano Novo muçulmano deste ano é amanhã (ao pôr-do-sol do dia 30/08/19),
acho que vale a pena aprender como lidar com a ligadura mais famosa do árabe:
a frase conhecida como <em>Sallallahou Alayhe Wasallam</em> que significa &ldquo;bênçãos de
Deus estejam sobre Ele e Sua família e paz&rdquo;. Esta frase é comumente conectada ao
nome dos profetas do Islã em sinal de respeito e, pela frequência de seu uso,
foi convertida em <strong>apenas um caractere</strong> Unicode: ﷺ</p>
<p>Faça um teste e copie o símbolo acima. Você pode notar que ele é de fato apenas
um glifo como qualquer outro e que pode ser enviado por qualquer WhatsApp da
vida!</p>
<p>A questão é que se estivermos analisando texto em árabe, esse tipo de ligadura
pode atrapalhar, por exemplo, a contagem de palavras. Para lidar com essas
situações (especificamente em árabe) usamos a função <code>stri_trans_nfkc()</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">stri_trans_nfkc</span><span class="p">(</span><span class="s">&#34;\ufdfa&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;صلى الله عليه وسلم&#34;</span></span></span></code></pre></div><p>E pronto! Agora nenhum feriado internacional vai pegar a sua programação de
surpresa.</p>
<p>Obs.: Acima utilizei o
<a href="https://www.utf8icons.com/character/65018/arabic-ligature-sallallahou-alayhe-wasallam">código Unicode da ligadura</a>
porque senão ela atrapalharia a formatação da caixa de código,
mas basta executar <code>cat(&quot;\ufdfa&quot;)</code> no seu R para ver que ele realmente
representa o S.A.W.</p>
]]></content:encoded>
    </item>
    <item>
      <title>IA &amp; chatbots</title>
      <link></link>
      <pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Web scraping orquestrado</title>
      <link>https://lente.dev/posts/scraper-orquestrado/</link>
      <pubDate>Tue, 14 May 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/scraper-orquestrado/</guid>
      <description>Uma introdução ao pacote Kuber: como usar o kubernetes e o Google Cloud Platform para fazer um scraper que roda na velocidade da luz.</description>
      <content:encoded><![CDATA[<p>O objetivo principal do pacote <a href="https://github.com/curso-r/kuber">Kuber</a> é
ajudar com computações massivamente paralelas. Ele usa o kubernetes e o
docker de modo a criar um contêiner que automaticamente executa tarefas em
paralelo via expansão. Se você já usa o Google Cloud Platform, o Kuber
também consegue automaticamente criar clusters, executar computações e
gerenciar o seu progresso com o Google cloud SDK.</p>
<p>Se você nunca ouviu falar sobre orquestração de contêineres, armazenamento
persistente na nuvem ou computação paralela, pode ser que esse tutorial
pareça avançado demais. Você não precisa ser nenhum especialista nesses
assuntos, mas ajuda pelo menos saber o que significam esses termos.</p>
<p>Esse tutorial vai te ajudar a criar a sua primeira tarefa do Kuber. Antes de
começar, certifique-se de que você instalou todos os requisitos corretamente
com a vignette
<a href="https://curso-r.github.io/kuber/articles/getting_started.html">&ldquo;Getting started&rdquo;</a></p>
<h2 id="a-tarefa-em-si">A tarefa em si</h2>
<p>A principal vantagem do Kuber em relação a outros pacotes de paralelização
(como Parallel ou Future/Furrr) é que ele automaticamente cria um cluster de
computadores que executa a sua tarefa via orquestração de contêineres. Isso
pode ser muito útil para web scraping, por exemplo, porque (1) cada máquina
tem um IP diferente, (2) salvar os HTMLs raspados é fácil com o Google Cloud
Storage e (3) o processo pode ser facilmente ativado/desativado a qualquer
momento.</p>
<p>Neste tutorial a função a ser paralelizada é a seguinte:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Scrapear um vetor de caracteres de URLs</span>
</span></span><span class="line"><span class="cl"><span class="n">scrape_urls</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">urls</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar um diretório</span>
</span></span><span class="line"><span class="cl">  <span class="n">dir</span> <span class="o">&lt;-</span> <span class="n">fs</span><span class="o">::</span><span class="nf">dir_create</span><span class="p">(</span><span class="s">&#34;scraped&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos URLs</span>
</span></span><span class="line"><span class="cl">  <span class="n">paths</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">url</span> <span class="kr">in</span> <span class="n">urls</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">path</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_remove_all</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="s">&#34;[^a-z]&#34;</span><span class="p">),</span> <span class="s">&#34;.html&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">paths</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">paths</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">httr</span><span class="o">::</span><span class="nf">GET</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">httr</span><span class="o">::</span><span class="nf">write_disk</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">overwrite</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">paths</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Em suma, essa função recebe um vetor de URLs, os raspa e salva os HTMLs
resultantes em um diretório local.</p>
<h2 id="criando-o-cluster">Criando o cluster</h2>
<p>Agora para o Kuber. Se tudo estiver instalado corretamente, você deveria ser
capaz de criar um cluster simples com o seguinte comando:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">kuber</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">kub_create_cluster</span><span class="p">(</span><span class="s">&#34;toy-cluster&#34;</span><span class="p">,</span> <span class="n">machine_type</span> <span class="o">=</span> <span class="s">&#34;f1-micro&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Creating cluster</span></span></span></code></pre></div><p>Vá para o
<a href="https://console.cloud.google.com/kubernetes/list">Kubernetes console</a> para
ver se tudo funcionou corretamente. Não se preocupe se você receber um monte
de alertas, a maioria deles é referente à versão do SDK.</p>
<h2 id="criando-a-tarefa">Criando a tarefa</h2>
<p>A função mais importante do Kuber provavelmente é a próxima. Ela cria um
diretório na sua máquina local que descreve a computação paralela e seus
cluster, pacote, imagem e conta de serviço. Para executar o comando abaixo,
apenas <code>toy-key.json</code> (a chave da conta de serviço baixada na vignette
&ldquo;Getting started&rdquo;) já precisa existir no caminho indicado; o resto é todo
criado para você.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">kub_create_task</span><span class="p">(</span><span class="s">&#34;~/toy-dir&#34;</span><span class="p">,</span> <span class="s">&#34;toy-cluster&#34;</span><span class="p">,</span> <span class="s">&#34;toy-bucket&#34;</span><span class="p">,</span> <span class="s">&#34;toy-image&#34;</span><span class="p">,</span> <span class="s">&#34;~/toy-key.json&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Fetching cluster information</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Fetching bucket information</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Creating bucket</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ●  Edit `~/toy-dir/exec.R`</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ●  Create `~/toy-dir/list.rds` with usable parameters</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ●  Run `kub_push_task(&#34;~/toy-dir&#34;)`</span></span></span></code></pre></div><h2 id="editando-o-execr-e-o-listrds">Editando o exec.R e o list.rds</h2>
<p>O diretório criado por <code>kub_create_task()</code> tem alguns arquivos que são
explorados em detalhe na documentação da própria função, mas os dois mais
importantes são <code>exec.R</code> e <code>list.rds</code>. O primeiro contém o arquivo R a ser
executado pela imagem docker, enquanto o segundo tem todos os objetos que
cada máquina precisa para rodar o seu próprio <code>exec.R</code>.</p>
<p>Começando pelo <code>exec.R</code>, o arquivo já está populado com um exemplo simples:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#!/usr/bin/env Rscript</span>
</span></span><span class="line"><span class="cl"><span class="n">args</span> <span class="o">&lt;-</span> <span class="nf">commandArgs</span><span class="p">(</span><span class="n">trailingOnly</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Arguments</span>
</span></span><span class="line"><span class="cl"><span class="n">idx</span> <span class="o">&lt;-</span> <span class="nf">as.numeric</span><span class="p">(</span><span class="n">args[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">bucket</span> <span class="o">&lt;-</span> <span class="nf">as.character</span><span class="p">(</span><span class="n">args[2]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Use this function to save your results</span>
</span></span><span class="line"><span class="cl"><span class="n">save_path</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">system</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;gsutil cp -r &#34;</span><span class="p">,</span> <span class="n">file_</span><span class="p">,</span> <span class="s">&#34; gs://&#34;</span><span class="p">,</span> <span class="n">bucket</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="nf">gsub</span><span class="p">(</span><span class="s">&#34;/.+&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="n">file_</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="nf">do.call</span><span class="p">(</span><span class="n">file.remove</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="nf">list.files</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">full.names</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Get object passed in list[[idx]]</span>
</span></span><span class="line"><span class="cl"><span class="n">obj</span> <span class="o">&lt;-</span> <span class="nf">readRDS</span><span class="p">(</span><span class="s">&#34;list.rds&#34;</span><span class="p">)</span><span class="n">[[idx]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">###########################</span>
</span></span><span class="line"><span class="cl"><span class="c1">## INSERT YOUR CODE HERE ##</span>
</span></span><span class="line"><span class="cl"><span class="c1">###########################</span></span></span></code></pre></div><p>Como você pode ver, é um Rscript que recebe dois argumentos: um índice e o
nome de um bucket GCS. O código em seguida descreve uma função a ser usada
quando salvando os resultados; ela envia o arquivo/diretório no <code>path</code> para
o bucket especificado e então o deleta do disco da máquina. Finalmente, o
script lê <code>list.rds</code> e seleciona o objeto guardado no índice <code>idx</code>.</p>
<p>Agora é hora de adicionar <code>scrape_urls()</code> para o arquivo. Não há muitas
mudanças na função em si, apenas em como os arquivos resultantes são
gerenciados. Aqui está a versão final do <code>exec.R</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#!/usr/bin/env Rscript</span>
</span></span><span class="line"><span class="cl"><span class="n">args</span> <span class="o">&lt;-</span> <span class="nf">commandArgs</span><span class="p">(</span><span class="n">trailingOnly</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Arguments</span>
</span></span><span class="line"><span class="cl"><span class="n">idx</span> <span class="o">&lt;-</span> <span class="nf">as.numeric</span><span class="p">(</span><span class="n">args[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">bucket</span> <span class="o">&lt;-</span> <span class="nf">as.character</span><span class="p">(</span><span class="n">args[2]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Use this function to save your results</span>
</span></span><span class="line"><span class="cl"><span class="n">save_path</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">system</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;gsutil cp -r &#34;</span><span class="p">,</span> <span class="n">file_</span><span class="p">,</span> <span class="s">&#34; gs://&#34;</span><span class="p">,</span> <span class="n">bucket</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="nf">gsub</span><span class="p">(</span><span class="s">&#34;/.+&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="n">file_</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="nf">do.call</span><span class="p">(</span><span class="n">file.remove</span><span class="p">,</span> <span class="nf">list</span><span class="p">(</span><span class="nf">list.files</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">full.names</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Get object passed in list[[idx]]</span>
</span></span><span class="line"><span class="cl"><span class="n">obj</span> <span class="o">&lt;-</span> <span class="nf">readRDS</span><span class="p">(</span><span class="s">&#34;list.rds&#34;</span><span class="p">)</span><span class="n">[[idx]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Scrapear um vetor de caracteres de URLs</span>
</span></span><span class="line"><span class="cl"><span class="n">scrape_urls</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">urls</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Criar um diretório</span>
</span></span><span class="line"><span class="cl">  <span class="n">dir</span> <span class="o">&lt;-</span> <span class="n">fs</span><span class="o">::</span><span class="nf">dir_create</span><span class="p">(</span><span class="s">&#34;scraped&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Iterar nos URLs</span>
</span></span><span class="line"><span class="cl">  <span class="n">paths</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">url</span> <span class="kr">in</span> <span class="n">urls</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">path</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_remove_all</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="s">&#34;[^a-z]&#34;</span><span class="p">),</span> <span class="s">&#34;.html&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">paths</span> <span class="o">&lt;-</span> <span class="nf">append</span><span class="p">(</span><span class="n">paths</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">httr</span><span class="o">::</span><span class="nf">GET</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">httr</span><span class="o">::</span><span class="nf">write_disk</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">overwrite</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">paths</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Rodar o scraper</span>
</span></span><span class="line"><span class="cl"><span class="n">paths</span> <span class="o">&lt;-</span> <span class="nf">scrape_urls</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Salvar os HTMLs no GCS</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">path</span> <span class="kr">in</span> <span class="n">paths</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">save_path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Como você já pode imaginar pelos chamados acima, <code>obj</code> contém os URLs a
serem raspados. Isso faz sentido porque, como descrito anteriormente,
<code>list.rds</code> tem todo objeto que cada máquina precisa para seu próprio
<code>exec.R</code>; neste caso, cada máquina precisa de um vetor de URLs a serem
scrapeados e <code>idx</code> é simplesmente o índice de cada máquina (para que duas
máquinas nunca raspem os mesmos URLs). É só isso.</p>
<p>Agora a única coisa que falta é criar o <code>list.rds</code>, ou seja, a lista de URLs
quebrada em um bloco para cada máquina. Como neste exemplo toy-cluster foi
criado com o número padrão de máquinas (3), <code>list.rds</code> vai ser uma lista
com 3 elementos. Os comandos a seguir devem ser rodados na sua máquina
local:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># URLs a serem raspados, blocados por máquina</span>
</span></span><span class="line"><span class="cl"><span class="n">url_list</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nf">c</span><span class="p">(</span><span class="s">&#34;google.com&#34;</span><span class="p">,</span> <span class="s">&#34;duckduckgo.com&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">c</span><span class="p">(</span><span class="s">&#34;wikipedia.org&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">c</span><span class="p">(</span><span class="s">&#34;facebook.com&#34;</span><span class="p">,</span> <span class="s">&#34;twitter.com&#34;</span><span class="p">,</span> <span class="s">&#34;instagram.com&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Sobrescrever o list.rds com a lista de URLs</span>
</span></span><span class="line"><span class="cl"><span class="n">readr</span><span class="o">::</span><span class="nf">write_rds</span><span class="p">(</span><span class="n">url_list</span><span class="p">,</span> <span class="s">&#34;~/toy-dir/list.rds&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Com esse <code>list.rds</code>, o primeiro nó vai raspar motores de busca, o segundo
vai raspar a Wikipédia e o terceiro vai raspar mídias sociais.</p>
<h2 id="dando-push-e-executando-a-tarefa">Dando push e executando a tarefa</h2>
<p>Por último mas não menos importante, a tarefa deve ser pushada para o Google
<a href="https://console.cloud.google.com/gcr/images">Container Registry</a> (GCR), que
é onde as imagens docker do Kuber vão ficar guardadas. Isso garante controle
de versão para todas as tarefas e permitem que elas sejam executadas de
outro computador, mas pode levar um bom tempo para rodar da primeira vez que
você cria uma tarefa.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">kub_push_task</span><span class="p">(</span><span class="s">&#34;~/toy-dir&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Building image</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Authenticating</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Pushing image</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Removing old jobs</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Creating new jobs</span></span></span></code></pre></div><p>Se tudo funcionou até agora, o último comando obrigatório é executar a
tarefa:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">kub_run_task</span><span class="p">(</span><span class="s">&#34;~/toy-dir&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Authenticating</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Setting cluster context</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Creating jobs</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ●  Run `kub_list_pods()` to follow up on the pods</span></span></span></code></pre></div><h2 id="gerenciando-o-progresso-da-tarefa">Gerenciando o progresso da tarefa</h2>
<p>A duas formas principais de gerenciar o progresso de uma tarefa: listando os
pods atualmente ativos e listando os arquivos guardados em um bucket. As
letras estranhas no nome de cada processo é um identificador único gerado
pelo Kuber para gerenciar aqueles pods.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">kub_list_pods</span><span class="p">(</span><span class="s">&#34;~/toy-dir&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Setting cluster context</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Fetching pods</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;                          NAME READY  STATUS RESTARTS AGE</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 1 process-mkewsr-item-1-8kpg7   1/1 Running        0  1m</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 2 process-mkewsr-item-2-cph8z   1/1 Running        0  1m</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 3 process-mkewsr-item-3-kpn5f   1/1 Running        0  1m</span></span></span></code></pre></div><p>Se o
<a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/">status dos seus pods</a>
indicar algo ruim, pode ser que você precise depurar o seu arquivo <code>exec.R</code>.
Isso é absolutamente normal e pode ser que sejam necessárias várias
tentativas até que a sua tarefa esteja rodando corretamente. Se você
precisar de ajuda na depuração da sua tarefa, dê uma olhada na vignette
<a href="https://curso-r.github.io/kuber/articles/debug_exec.html">&ldquo;Debugging exec.R&rdquo;</a>.</p>
<p>O comando abaixo lista todo arquivo em um bucket. Você também pode
especificar o diretório dentro do bucket e se a listagem deve ser feita
recursivamente. Aqui é possível ver que todo download terminou de rodar
corretamente.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">kub_list_bucket</span><span class="p">(</span><span class="s">&#34;~/toy-dir&#34;</span><span class="p">,</span> <span class="n">folder</span> <span class="o">=</span> <span class="s">&#34;scraped&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; ✔  Listing content</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;googlecom.html&#34;     &#34;duckduckgocom.html&#34; &#34;wikipediaorg.html&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [4] &#34;facebookcom.html&#34;   &#34;twittercom.html&#34;    &#34;instagramcom.html&#34;</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Métricas de polarização</title>
      <link></link>
      <pubDate>Sun, 12 May 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Visualização de dados</title>
      <link></link>
      <pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Conclusão de curso</title>
      <link></link>
      <pubDate>Mon, 10 Dec 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Por que usar o %&gt;%</title>
      <link>https://lente.dev/posts/porque-pipe/</link>
      <pubDate>Thu, 28 Jun 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/porque-pipe/</guid>
      <description>Uma breve história do pipe (%&amp;gt;%) e porque ele é uma ótima ferramenta para simplificar análises de dados.</description>
      <content:encoded><![CDATA[<p>Provavelmente você já ouviu falar do operador pipe (<code>%&gt;%</code>). Muita gente acha
que ele é uma sequência mágica de símbolos que muda completamente o visual do
seu código, mas na verdade ele não passa de uma função como outra qualquer.</p>
<p>Nesse post vou explorar um pouco da história do pipe, como ele funciona e
por que utilizá-lo.</p>
<h2 id="origem">Origem</h2>
<p>O conceito de pipe existe pelo menos desde os anos 1970. De acordo com seu
criador, o operador foi concebido em &ldquo;uma noite febril&rdquo; e tinha o objetivo de
simplificar comandos cujos resultados deveriam ser passados para outros
comandos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">ls <span class="p">|</span> cat
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Desktop</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Documents</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Downloads</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Music</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Pictures</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Public</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Templates</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Videos</span></span></span></code></pre></div><p>Por essa descrição já conseguimos ter uma ideia de onde vem o seu nome: <em>pipe</em>
em inglês significa &ldquo;cano&rdquo;, referindo-se ao transporte das saídas dos comandos.
Em português o termo é traduzido como &ldquo;canalização&rdquo; ou &ldquo;encadeamento&rdquo;, mas
no dia-a-dia é mais comum usar o termo em inglês.</p>
<p>A partir daí o pipe tem aparecido nas mais diversas aplicações, desde HTML até
o nosso tão querido R. Ele pode ter múltiplos disfarces, mas o seu objetivo
é sempre o mesmo: transportar resultados.</p>
<h2 id="como-funciona">Como funciona</h2>
<p>Em R o pipe tem uma cara meio estranha (<code>%&gt;%</code>), mas no fundo ele não passa
de uma função infixa, ou seja, uma função que aparece entre os seus argumentos
(como <code>a + b</code> ou <code>a %in% b</code>). Na verdade é por isso mesmo que ele tem
porcentagens antes e depois: porque no R uma função infixa só pode ser
declarada assim.</p>
<p>Vamos começar demonstrando sua funcionalidade básica. Carregue o pacote
<code>magrittr</code> e declare o pipe usando <em>Ctrl + Shift + M</em>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">magrittr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">`%&gt;%`</span><span class="p">(</span><span class="s">&#34;oi&#34;</span><span class="p">,</span> <span class="n">print</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;oi&#34;</span></span></span></code></pre></div><p>Não ligue para os acentos graves em volta do pipe, o comando acima só serve
para demonstrar que ele não é nada mais que uma função; perceba que o seu
primeiro (<code>&quot;oi&quot;</code>) argumento virou a entrada do seu segundo argumento (<code>print</code>).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;oi&#34;</span> <span class="o">%&gt;%</span> <span class="nf">print</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;oi&#34;</span></span></span></code></pre></div><p>Observe agora o comando abaixo. Queremos primeiro somar 3 a uma sequência de
números e depois dividí-los por 2:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">mais_tres</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">+</span> <span class="m">3</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">sobre_dois</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">/</span> <span class="m">2</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">&lt;-</span> <span class="m">1</span><span class="o">:</span><span class="m">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">sobre_dois</span><span class="p">(</span><span class="nf">mais_tres</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2.0 2.5 3.0</span></span></span></code></pre></div><p>Perceba como fica difícil de entender o que está acontecendo primeiro? A linha
relevante começa com a divisão por 2, depois vem a soma com 3 e, por fim, os
valores de entrada.</p>
<p>Nesse tipo de situação é mais legível usar a notação de
<a href="https://pt.wikipedia.org/wiki/Composi%C3%A7%C3%A3o_de_fun%C3%A7%C3%B5es">composição de funções</a>,
com as funções sendo exibidas na ordem em que serão aplicadas:


<math><mrow><mi>f</mi><mo>∘</mo><mi>g</mi></mrow></math>
.</p>
<p>Isso pode ser realizado se tivermos uma função que passa o resultado do que está
à sua esquerda para a função que está à sua direita&hellip;</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">x</span> <span class="o">%&gt;%</span> <span class="nf">mais_tres</span><span class="p">()</span> <span class="o">%&gt;%</span> <span class="nf">sobre_dois</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2.0 2.5 3.0</span></span></span></code></pre></div><p>No comando acima fica evidente que pegamos o objeto <code>x</code>, somamos 3 e dividimos
por 2.</p>
<p>Você pode já ter notado isso, mas a entrada (esquerda) de um pipe sempre é
passada como o <em>primeiro</em> argumento da sua saída (direita). Isso não
impede que as funções utilizadas em uma sequência de pipes tenham outros
argumentos.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">soma_n</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">+</span> <span class="n">n</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">%&gt;%</span> <span class="nf">mais_n</span><span class="p">(</span><span class="m">4</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">sobre_dois</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2.5 3.0 3.5</span></span></span></code></pre></div><h2 id="vantagens">Vantagens</h2>
<p>A grande vantagem do pipe não é só enxergar quais funções são aplicadas
primeiro, mas sim nos ajudar a programar pipelines (&ldquo;encanamento&rdquo; em inglês)
de tratamentos de dados.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">starwars</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mutate</span><span class="p">(</span><span class="n">bmi</span> <span class="o">=</span> <span class="n">mass</span><span class="o">/</span><span class="p">((</span><span class="n">height</span><span class="o">/</span><span class="m">100</span><span class="p">)</span><span class="n">^2</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">select</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">bmi</span><span class="p">,</span> <span class="n">species</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">group_by</span><span class="p">(</span><span class="n">species</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarise</span><span class="p">(</span><span class="n">bmi</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="n">bmi</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # A tibble: 38 x 2</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    species     bmi</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;    &lt;chr&gt;     &lt;dbl&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  1 Aleena     24.0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  2 Besalisk   26.0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  3 Cerean     20.9</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  4 Chagrian   NA</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  5 Clawdite   19.5</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  6 Droid      NA</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  7 Dug        31.9</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  8 Ewok       25.8</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  9 Geonosian  23.9</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; 10 Gungan     NA</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; # ... with 28 more rows</span></span></span></code></pre></div><p>Acima fica extremamente claro o que está acontecendo em cada passo da pipeline.
Partindo da base <code>starwars</code>, primeiro transformamos, depois selecionamos,
agrupamos e resumimos; em cada linha temos uma operação e elas são executadas
em sequência.</p>
<p>Isso não melhora só a legibilidade do código, mas também a sua <em>debugabilidade</em>!
Se tivermos encontrado um bug na pipeline, basta executar linha a linha do
encadeamento até que encontremos a linha problemática. Com o pipe podemos
programar de forma mais compacta, legível e correta.</p>
<p>Todos os exemplos acima envolvem passar a entrada do pipe como o primeiro
argumento da função à direita, mas não é uma obrigatoriedade. Com um operador
placeholder <code>.</code> podemos indicar exatamente onde deve ser colocado o valor
que chega no pipe:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">y_menos_x</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> <span class="n">y</span> <span class="o">-</span> <span class="n">x</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mais_tres</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map2</span><span class="p">(</span><span class="m">4</span><span class="o">:</span><span class="m">6</span><span class="p">,</span> <span class="n">.,</span> <span class="n">y_menos_x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 0</span></span></span></code></pre></div><h2 id="bônus">Bônus</h2>
<p>Agora que você já sabe dos usos mais comuns do pipe, aqui está uma outra
funcionalidade interessante: funções unárias. Se você estiver familiarizado
com o <a href="http://lente.dev/magica-purrr/">pacote <code>purrr</code></a>, esse é um jeito
bastante simples de criar funções descartáveis.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">m3_s2</span> <span class="o">&lt;-</span> <span class="n">. </span><span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mais_tres</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sobre_dois</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">m3_s2</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 2.0 2.5 3.0</span></span></span></code></pre></div><p>Usando novamente o <code>.</code> definimos uma função que recebe apenas um argumento
com uma sequência de aplicações de outras funções.</p>
<h2 id="conclusão">Conclusão</h2>
<p>O pipe não é apenas algo que deve ser usado pelos fãs do
<a href="https://www.tidyverse.org/">tidyverse</a>. Ele é uma função extremamente útil
que ajuda na legibilidade e programação de código, independentemente de
quais pacotes utilizamos.</p>
<p>Se quiser saber mais sobre o mundo do pipe, leia
<a href="http://curso-r.com/blog/2017/02/15/2017-02-16-manifesto-tidy/">este post</a>
do Daniel sobre o Manifesto Tidy e o
<a href="http://material.curso-r.com/pipe/">nosso tutorial</a> mais aprofundado sobre o
próprio pipe.</p>
]]></content:encoded>
    </item>
    <item>
      <title>API para quebrar captchas</title>
      <link></link>
      <pubDate>Tue, 22 May 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Estruturas de dados distribuídas em R</title>
      <link></link>
      <pubDate>Tue, 22 May 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Purrr avançado</title>
      <link></link>
      <pubDate>Mon, 09 Apr 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Web scraping em R pt. 1</title>
      <link></link>
      <pubDate>Sat, 10 Mar 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>O fluxo do web scraping</title>
      <link>https://lente.dev/posts/fluxo-scraping/</link>
      <pubDate>Sun, 18 Feb 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/fluxo-scraping/</guid>
      <description>Uma breve introdução ao fluxo do webscraping, um passo-a-passo para entender como um raspador deve funcionar.</description>
      <content:encoded><![CDATA[<p><em>Web scraping</em> (ou raspagem web) não é nada mais que o ato de coletar dados da
internet. Hoje em dia é muito comum termos acesso rápido e fácil a qualquer
conjunto de informações pela web, mas raramente esses dados estão estruturados
e em uma forma de fácil obtenção pelo usuário.</p>
<p>Isso faz com que precisemos aprender a coletar esses dados por conta própria.
Neste post vou descrever o <strong>fluxo do web scraping</strong>, um passo a passo para
explicar aos iniciantes como funciona a criação de um raspador.</p>
<h2 id="o-fluxo">O fluxo</h2>
<p>Caso você já tenha visto o
<a href="http://r4ds.had.co.nz/introduction.html">fluxo da ciência de dados</a>
descrito por Hadley Wickham, o fluxo do web scraping vai ser bastante simples
de entender. Todos os itens a seguir vão se basear neste diagrama:</p>
<figure><img src="https://lente.dev/posts/scraping-cycle/cycle.webp"/>
</figure>
<p>Cada verbo indica um fase do processo de raspar dados da internet. A caixa
azulada no meio do diagrama denominada <strong>reprodução</strong> indica um procedimento
iterativo que devemos repetir até que a coleta funcione, mas, de resto, o fluxo
é um processo linear.</p>
<p>Nas próximas seções, vamos explorar um exemplo bem simples para entender como
esses passos se dariam no mundo real: extrair os títulos de artigos da Wikipédia.</p>
<h3 id="identificar">Identificar</h3>
<p>O primeiro passo do fluxo se chama <strong>identificar</strong> porque nele identificamos
a informação que vamos coletar. Aqui precisamos entender bem qual é a estrutura
das páginas que queremos raspar e traçar um plano para extrair tudo que
precisamos.</p>
<p>No nosso exemplo, precisaríamos entrar em algumas páginas da Wikipédia para
entender se os títulos se comportam da mesma forma em todas. Como a Wikipédia
é um site organizado, todos os títulos são criados da mesma forma em
absolutamente todos os artigos.</p>
<figure><img src="https://lente.dev/posts/scraping-cycle/title.gif"/>
</figure>
<h3 id="navegar">Navegar</h3>
<p>Agora precisamos entender de onde vem o dado que queremos extrair. Esse passo
pode ser extremamente simples simples, mas de vez em quando ele se tornara algo
bastante complexo.</p>
<p>Usando as ferramentas de desenvolvedor do nosso navegador, vamos <strong>navegar</strong>
para encontrar a fonte dos dados. Sem entrar em muitos detalhes, poderíamos
analisar o <em>networking</em> do navegador para entender as chamadas HTTP que são
feitas, poderíamos estudar os resultados das funções JavaScript invocadas
pela página e assim por diante.</p>
<p>No nosso caso, como escolhi um exemplo simples, precisamos apenas inspecionar
o elemento do título e ver qual é o seu
<a href="https://en.wikipedia.org/wiki/XPath">XPath</a> (basicamente o endereço do elemento
no HTML da página): <code>//*[@id=&quot;firstHeading&quot;]</code>.</p>
<figure><img src="https://lente.dev/posts/scraping-cycle/inspect.gif"/>
</figure>
<h3 id="replicar">Replicar</h3>
<p>Se tivéssemos que fazer várias requests HTTP para chegar até a informação que
queremos, seria aqui em que tentaríamos <strong>replicar</strong> essas chamadas. Neste
passo é importante compreender absolutamente tudo que a página está fazendo
para trazer o conteúdo até você, então é necessário analisar o seu <em>networking</em>
a fim de entender tais requests e seus respectivos queries.</p>
<p>No nosso caso, basta fazer uma chamada GET para obter a página do artigo
desejado. Também se faz necessário salvar a página localmente para que
possamos dar continuidade ao fluxo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">url</span> <span class="o">&lt;-</span> <span class="s">&#34;https://en.wikipedia.org/wiki/R_(programming_language)&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">httr</span><span class="o">::</span><span class="nf">GET</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">httr</span><span class="o">::</span><span class="nf">write_disk</span><span class="p">(</span><span class="s">&#34;~/Desktop/wiki.html&#34;</span><span class="p">))</span></span></span></code></pre></div><h3 id="parsear">Parsear</h3>
<p>O anglicismo <strong>parsear</strong> vem do verbo <em>to parse</em>, que quer dizer algo como
analisar ou estudar, mas que, no contexto do web scraping, significa extrair
os dados desejados de um arquivo HTML.</p>
<p>Aqui vamos usar a informação obtida no passo 2 para retirar do arquivo que
chamei de <code>wiki.html</code> o título do artigo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="s">&#34;~/Desktop/wiki.html&#34;</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">xml2</span><span class="o">::</span><span class="nf">read_html</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">rvest</span><span class="o">::</span><span class="nf">html_node</span><span class="p">(</span><span class="n">xpath</span> <span class="o">=</span> <span class="s">&#34;//*[@id=&#39;firstHeading&#39;]&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">rvest</span><span class="o">::</span><span class="nf">html_text</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;R (programming language)&#34;</span></span></span></code></pre></div><h3 id="validar">Validar</h3>
<p>Se tivermos feito tudo certo até agora, <strong>validar</strong> os resultados será uma
tarefa simples. Precisamos apenas reproduzir o procedimento descrito até
agora para algumas outras páginas de modo verificar se estamos de fato
extraindo corretamente tudo o que queremos.</p>
<p>Caso encontremos algo de errado precisamos voltar ao passo 3, tentar replicar
corretamente o comportamento do site e parsear os dados certos nas páginas.</p>
<h3 id="iterar">Iterar</h3>
<p>O último passo consiste em colocar o nosso scraper em produção. Aqui, ele já
deve estar funcionando corretamente para todos os casos desejados e estar
pronto para raspar todos os dados dos quais precisamos.</p>
<p>Na maior parte dos casos isso consiste em encapsular o scraper em uma função
que recebe uma série de links e aplica o mesmo procedimento em cada um. Se
quisermos aumentar a eficiência desse processo, podemos
<a href="http://lente.dev/scraper-distribuido/">paralelizar ou distribuir</a> o
nosso raspador.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">scraper</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">httr</span><span class="o">::</span><span class="nf">GET</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">httr</span><span class="o">::</span><span class="nf">write_disk</span><span class="p">(</span><span class="n">path</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">path</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">xml2</span><span class="o">::</span><span class="nf">read_html</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">rvest</span><span class="o">::</span><span class="nf">html_node</span><span class="p">(</span><span class="n">xpath</span> <span class="o">=</span> <span class="s">&#34;//*[@id=&#39;firstHeading&#39;]&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">rvest</span><span class="o">::</span><span class="nf">html_text</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">purrr</span><span class="o">::</span><span class="nf">map2_chr</span><span class="p">(</span><span class="n">links</span><span class="p">,</span> <span class="n">paths</span><span class="p">,</span> <span class="n">scraper</span><span class="p">)</span></span></span></code></pre></div><h2 id="conclusão">Conclusão</h2>
<p>Fazer um scraper não é uma tarefa fácil, mas, se toda vez seguirmos um
método consistente e robusto, podemos melhorar um pouco o nosso trabalho.
O fluxo do web scraping tenta ser este método, englobando em passos simples
e razoavelmente bem definidos essa arte que é fazer raspadores web.</p>
<p>Caso você tenha se interessado pelo conteúdo abordado nesse post, eu e o
pessoal da Curso-R vamos dar no dia 10/03/2018 um workshop em São Paulos sobre
web scraping com R. Lá você vai ter a oportunidade de aprender em muitos mais
detalhes como são, no mundo real, os 6 passos do web scraping além de várias
dicas de como tornar seus scrapers ainda melhores.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Web scraping distribuído</title>
      <link>https://lente.dev/posts/scraper-distribuido/</link>
      <pubDate>Fri, 16 Feb 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/scraper-distribuido/</guid>
      <description>Várias vezes o volume de dados a ser raspado da internet é muito grande e, portanto, é necessário paralelizar e distribuir um scraper.</description>
      <content:encoded><![CDATA[<p>Caso você já tenha se aventurado no mundo do web scraping, é provável que
tenha se deparado com um grande problema: volume. Muitas vezes, antes fazer uma
análise, precisamos scrapear um número colossal de páginas até que tenhamos
dados o suficiente para a nossa tarefa, número esse que chega a ser proibitivo
a ponto de não conseguirmos fazer aquilo que queremos.</p>
<p>Neste post vou explicar duas técnicas para aumentar em dezenas de vezes a
velocidade dos seus scrapers de forma que você nunca mais precise de preocupar
com a quantidade de dados necessária para uma análise.</p>
<h2 id="scrapers-sequenciais">Scrapers sequenciais</h2>
<p>Um scraper sequencial é qualquer scraper que baixe uma página por vez, ou seja,
que varra as páginas em sequência baixando uma a uma. Como veremos na seção a
seguir isso não é muito eficiente, mas é mesmo assim o que a maioria de nós faz.</p>
<p><strong>Nota:</strong> Nos exemplos que darei daqui em diante estarei baixando uma lista de
1441 artigos da Wikipédia obtida com o pacote <code>WikipediR</code>. Se você quiser
reproduzir os meus achados, disponibilizei um arquivo com o código completo em
um <a href="https://gist.github.com/clente/84f230a88cae01537ac5ca4eff091221">Gist</a></p>
<p>Veja mais ou menos como funcionaria para baixar um link da Wikipédia por vez:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Função para baixar uma página da Wikipédia</span>
</span></span><span class="line"><span class="cl"><span class="n">download_wiki</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Converter um URL em um nome de arquivo</span>
</span></span><span class="line"><span class="cl">  <span class="n">file</span> <span class="o">&lt;-</span> <span class="n">url</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">utils</span><span class="o">::</span><span class="nf">URLdecode</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_extract</span><span class="p">(</span><span class="s">&#34;(?&lt;=/)[^/]+$&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span><span class="s">&#34;[:punct:]&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_to_lower</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="nf">normalizePath</span><span class="p">(</span><span class="n">path</span><span class="p">),</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="n">.,</span> <span class="s">&#34;.html&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Salvar a página no disco</span>
</span></span><span class="line"><span class="cl">  <span class="n">httr</span><span class="o">::</span><span class="nf">GET</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">httr</span><span class="o">::</span><span class="nf">write_disk</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="kc">TRUE</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Baixar arquivos sequencialmente</span>
</span></span><span class="line"><span class="cl"><span class="n">files</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">links</span><span class="p">,</span> <span class="n">download_wiki</span><span class="p">,</span> <span class="s">&#34;~/Desktop/Wiki&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Nada muito complexo até aí. Com a <code>purrr::map_chr()</code> itero com facilidade nos
links e os baixo sequencialmente (se você quiser saber mais sobre a função
<code>map()</code> veja <a href="http://lente.dev/magica-purrr/">este post</a>). O código acima
demorou mais ou menos 5 minutos para executar na minha máquina.</p>
<h2 id="scrapers-em-paralelo">Scrapers em paralelo</h2>
<p>Uma das formas mais simples de aumentar a eficiência de um web scraper é através
de paralelização. Um fato que nem todos sabem é que praticamente qualquer scraper
passa a maior parte do tempo esperando respostas do servidor; seja para carregar
uma nova página ou seja para baixar a página em questão, ficar esperando é o que
o seu scraper provavelmente mais faz.</p>
<p>Isso quer dizer que seu computador poderia ter, em qualquer dado momento, múltiplos
scrapers rodando simultaneamente sem perder eficiência! Enquanto o processador está
salvando no disco os resultados de um scraper, é perfeitamente possível ter muitos
outros ativos e esperando uma resposta do servidor.</p>
<p>No exemplo de código abaixo uso uma função muito simples para paralelizar a
execução do scraper. <code>parallel::mcmapply()</code> (<em>multicore mapply()</em>) é análoga a
<code>map()</code>, com a diferença de que ela instancia as chamadas para a função
<code>download_wiki()</code> em múltiplos threads de execução, tirando vantagem do fato
de que cada instância fica parada a maior parte do tempo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar uma versão empacotada de download_wiki()</span>
</span></span><span class="line"><span class="cl"><span class="n">download_wiki_</span> <span class="o">&lt;-</span> <span class="n">purrr</span><span class="o">::</span><span class="nf">partial</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">download_wiki</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="s">&#34;~/Desktop/Wiki&#34;</span><span class="p">,</span> <span class="n">.first</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Baixar arquivos em paralelo</span>
</span></span><span class="line"><span class="cl"><span class="n">files</span> <span class="o">&lt;-</span> <span class="n">parallel</span><span class="o">::</span><span class="nf">mcmapply</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">download_wiki_</span><span class="p">,</span> <span class="n">links</span><span class="p">,</span> <span class="n">SIMPLIFY</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">,</span> <span class="n">mc.cores</span> <span class="o">=</span> <span class="m">4</span><span class="p">)</span></span></span></code></pre></div><p>No código acima, crio uma versão pré-preenchida de <code>download_wiki()</code> para não
precisar lidar com argumentos constantes na chamada para <code>parallel::mcmapply()</code>,
mas depois disso a única coisa que preciso fazer é especificar o número de
cores disponíveis no meu computador para que o pacote <code>parallel</code> faça a sua
magia. Desta forma, com uma chamada marginalmente mais complexa, consegui
baixar os mesmos arquivos em meros 1.2 minutos.</p>
<h2 id="scrapers-distribuídos">Scrapers distribuídos</h2>
<p>Para o nosso <em>grand finale</em> temos um pequeno salto de dificuldade. Agora que
somos capazes de usar todo o potencial do nosso computador, a única forma de
fazer scraping mais rápido é usando <strong>mais</strong> computadores.</p>
<p>Isso parece loucura, mas usando máquinas virtuais da
<a href="https://aws.amazon.com/pt/ec2/">Amazon</a> ou da
<a href="https://cloud.google.com/compute/">Google</a> essa é na verdade uma tarefa
bastante simples! Podemos criar algumas instâncias virtuais e enviar os
links para que elas os baixem, distribuindo o download entre várias
máquinas.</p>
<figure><img src="https://lente.dev/posts/distributed-scraper/scheme.webp"/>
</figure>
<p>Para permitir que uma máquina virtual receba o comando de download, criei
um pequeno servidor HTTP em cada uma, assim elas ficarão esperando por
uma chamada POST contendo os URLs a serem baixados.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Trecho do código em python do servidor que lida com POSTs</span>
</span></span><span class="line"><span class="cl"><span class="n">def</span> <span class="nf">do_POST</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">content_length</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">self.headers[</span><span class="s">&#39;Content-Length&#39;</span><span class="n">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">post_data</span> <span class="o">=</span> <span class="nf">self.rfile.read</span><span class="p">(</span><span class="n">content_length</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">call</span><span class="p">(</span><span class="n">[</span><span class="s">&#34;Rscript&#34;</span><span class="p">,</span> <span class="s">&#34;~/script.R&#34;</span><span class="p">,</span> <span class="n">post_data]</span><span class="p">)</span></span></span></code></pre></div><p>Como pode-se ver no código acima, a única coisa que o servidor faz é
coletar os dados enviados pelo post e redirecioná-los para o script
<code>script.R</code>. Lá o R coleta os links vindos de <code>post_data</code> e os baixa
(usando, é claro, <code>parallel::mcmapply</code>).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#!/usr/bin/env Rscript</span>
</span></span><span class="line"><span class="cl"><span class="n">args</span> <span class="o">=</span> <span class="nf">commandArgs</span><span class="p">(</span><span class="n">trailingOnly</span><span class="o">=</span><span class="kc">TRUE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Tratar o pacote de dados enviado no POST</span>
</span></span><span class="line"><span class="cl"><span class="n">links</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_split</span><span class="p">(</span><span class="n">args[1]</span><span class="p">,</span> <span class="s">&#34; &#34;</span><span class="p">)</span><span class="n">[[1]]</span></span></span></code></pre></div><p>Acima temos a única diferença no código em R (que agora se encontra nas máquinas
virtuais): o tratamento necessário em <code>script.R</code> dos dados trazidos pela chamada
POST.</p>
<p>O último passo é, em nossa máquina local, quebrar a lista de links em um pacote
para cada máquina serva; assim que as máquinas receberem esses links via HTTP
elas começarão, distribuidamente, a baixá-los em paralelo.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Quebrar os links de acordo com o número de servos</span>
</span></span><span class="line"><span class="cl"><span class="n">num_workers</span> <span class="o">&lt;-</span> <span class="m">3</span>
</span></span><span class="line"><span class="cl"><span class="n">links_split</span> <span class="o">&lt;-</span> <span class="n">links</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">split</span><span class="p">(</span><span class="n">.,</span> <span class="nf">ceiling</span><span class="p">(</span><span class="nf">seq_along</span><span class="p">(</span><span class="n">.)</span><span class="o">/</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">.)</span><span class="o">/</span><span class="n">num_workers</span><span class="p">)))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">purrr</span><span class="o">::</span><span class="nf">map</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="n">str_c</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Dados do endpoint</span>
</span></span><span class="line"><span class="cl"><span class="n">workers</span> <span class="o">&lt;-</span> <span class="s">&#34;localhost&#34;</span> <span class="c1"># AQUI VÃO OS IPS DOS SERVOS</span>
</span></span><span class="line"><span class="cl"><span class="n">endpoints</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="s">&#34;http://&#34;</span><span class="p">,</span> <span class="n">workers</span><span class="p">,</span> <span class="s">&#34;:8000&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Chamar todos os servos mas não esperar por eles</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_len</span><span class="p">(</span><span class="n">num_workers</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">command</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;curl -d &#39;&#34;</span><span class="p">,</span> <span class="n">links_split[[i]]</span><span class="p">,</span> <span class="s">&#34;&#39; &#34;</span><span class="p">,</span> <span class="n">endpoints[i]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">system</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">wait</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Usando 3 máquinas virtuais de 4 cores cada no Google Cloud Platform, o download
das 1400 páginas demorou meros 34 segundos. Isso é uma melhora de aproximadamente
10 vezes na performance em relação à execução sequencial!</p>
<h2 id="conclusão">Conclusão</h2>
<p>Como vimos nos exemplos acima, scrapers são por padrão processos lentos e
ineficientes. Usando uma arquitetura razoavelmente simples distribuída e paralela
podemos aumentar em até uma ordem de grandeza a eficiência de um scraper sem nem
pensar sobre o seu código! Na prática, podemos aumentar e diminuir o quanto
quisermos o número de servos ou de cores em cada servo, permitindo que qualquer
scraper possa virar uma máquina incrível de coleta de dados.</p>
<p>Caso você tenha se interessado pelo conteúdo abordado nesse post, eu e o pessoal
da <a href="http://curso-r.com/">Curso-R</a> vamos dar no dia 10/03/2018 um workshop
em São Paulos sobre <a href="http://workshop.curso-r.com/web-scraping/">web scraping com R</a>.
Lá você vai ter a oportunidade de aprender, do zero, como fazer bons web scrapers
em R além de muitas dicas como a desse post para tornar seus scrapers ainda melhores.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Pacotes R</title>
      <link></link>
      <pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Stringr, lubridate e purrr</title>
      <link></link>
      <pubDate>Fri, 02 Feb 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Stringr e lubridate</title>
      <link></link>
      <pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid></guid>
      <description></description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    <item>
      <title>Fazendo o R voar com Rcpp</title>
      <link>https://lente.dev/posts/intro-rcpp/</link>
      <pubDate>Wed, 22 Nov 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/intro-rcpp/</guid>
      <description>Uma introdução ao Rcpp, um pacote de R que funciona como interface entre o R e o C++ para fazer tudo rodar mais rápido.</description>
      <content:encoded><![CDATA[<p>O que fazer quando precisamos que o nosso script rode mais rápido? Geralmente a primeira ideia que temos é otimizar o código: reduzir a quantidade de laços, diminuir o tamanho das estruturas, utilizar programação paralela, etc&hellip; Mas quando se trata de R, temos a possibilidade de aumentar a velocidade do código sem alterar praticamente nada da sua estrutura.</p>
<p>Neste post darei uma introdução básica ao pacote <code>Rcpp</code>, uma ferramenta que nos permite rodar código em C++ de dentro do R.</p>
<h2 id="o-básico">O básico</h2>
<p>C++ é uma linguagem de programação muito famosa e versátil. Ela têm elementos de programação genérica, imperativa e orientada a objeto e também fornece uma interface para manipulação de memória de baixo nível.</p>
<p>Uma característica interessante do C++ é que ele é <em>extremamente</em> veloz. Diferentemente do R, ela é uma linguagem compilada, com tipagem estática e que não fornece tantas abstrações de operações, permitindo que seu código execute com eficiência incrível.</p>
<p>Para explorar os benefícios que o C++ pode trazer para o seu código R, instale e carregue o pacote <code>Rcpp</code> com os comandos abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;Rcpp&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">Rcpp</span><span class="p">)</span></span></span></code></pre></div><p>Vejamos agora um exemplo simples de como chamar código C++ do R. O jeito mais fácil de fazer isso é através da função <code>cppFunction()</code>: ela recebe uma string que será interpretada como uma função em C++.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">adicao_r</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">sum</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span>
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">cppFunction</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;int adicao_c(int x, int y, int z) {
</span></span></span><span class="line"><span class="cl"><span class="s">    int sum = x + y + z;
</span></span></span><span class="line"><span class="cl"><span class="s">    return sum;
</span></span></span><span class="line"><span class="cl"><span class="s">  }&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">adicao_r</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 6</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">adicao_c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 6</span></span></span></code></pre></div><p>Como podemos observar no exemplo acima, ambas as funções têm o mesmo comportamento apesar de algumas diferenças superficiais. Note como temos sempre que declarar os tipos das variáveis em C++! Usando a palavra-chave <code>int</code> deixamos claro para o compilador que uma variável terá o tipo inteiro e até mesmo que uma função deve retornar um valor de tipo inteiro. Outra coisa que é importante lembrar é que precisamos colocar um ponto-e-vírgula após cada comando C++.</p>
<h2 id="vetores">Vetores</h2>
<p>Normalmente o C++ teria diferenças enormes em relação ao R no seu tratamento de vetores, mas para a nossa sorte o <code>Rcpp</code> nos disponibiliza uma biblioteca de estruturas que abstraem o comportamento do R. No exemplo a seguir temos uma função que recebe um número e vetor numérico, computa a distância euclidiana entre o valor e o vetor e retorna um vetor numérico como saída.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">dist_r</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">ys</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sqrt</span><span class="p">((</span><span class="n">x</span> <span class="o">-</span> <span class="n">ys</span><span class="p">)</span> <span class="n">^</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">cppFunction</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;NumericVector dist_c(double x, NumericVector ys) {
</span></span></span><span class="line"><span class="cl"><span class="s">    int n = ys.size();
</span></span></span><span class="line"><span class="cl"><span class="s">    NumericVector out(n);
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    for(int i = 0; i &lt; n; i++) {
</span></span></span><span class="line"><span class="cl"><span class="s">      out[i] = sqrt(pow(ys[i] - x, 2.0));
</span></span></span><span class="line"><span class="cl"><span class="s">    }
</span></span></span><span class="line"><span class="cl"><span class="s">    return out;
</span></span></span><span class="line"><span class="cl"><span class="s">  }&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">dist_r</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="m">20</span><span class="o">:</span><span class="m">25</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 10 11 12 13 14 15</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">dist_c</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="m">20</span><span class="o">:</span><span class="m">25</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] 10 11 12 13 14 15</span></span></span></code></pre></div><p>A estrutura <code>NumericVector</code> abstrai um vetor numérico do R, nos permitindo trabalhar com ele de uma maneira mais familiar. Com o método <code>.size()</code> obtemos o seu comprimento (equivalente a <code>length()</code>) e podemos declarar um novo com o construtor <code>NumericVector nome(comprimento);</code>. O único ponto de diferença fundamental entre o C++ e o R é que o primeiro não possui operações vetorizadas propriamente ditas, fazendo com que precisemos usar laços para toda e qualquer iteração.</p>
<h2 id="velocidade-máxima">Velocidade máxima</h2>
<p>Certos aspectos da filosofia do R o tornam uma linguagem extremamente versátil, mas isso vem com certas desvantagens. Alguns pontos em que a performance do R deixa a desejar são laço não vetorizáveis (por uma iteração depender da anterior), funções recursivas e estruturas de dados complexas.</p>
<p>Nestas e em muitas outras situações, usar C++ pode ser extremamente vantajoso. No exemplo a seguir veremos a diferença entre a performance de um laço em C++ e um em R; note que esta nem é uma das 3 situações listadas no parágrafo anterior e que mesmo assim o código em C++ é <em>6 vezes mais rápido</em>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">soma_r</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">total</span> <span class="o">&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">  <span class="kr">for</span> <span class="p">(</span><span class="n">e</span> <span class="kr">in</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="p">(</span><span class="n">e</span> <span class="o">&lt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span> <span class="n">total</span> <span class="o">=</span> <span class="n">total</span> <span class="o">-</span> <span class="n">e</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="kr">else</span> <span class="kr">if</span> <span class="p">(</span><span class="n">e</span> <span class="o">&gt;</span> <span class="m">0.75</span><span class="p">)</span> <span class="p">{</span> <span class="n">total</span> <span class="o">=</span> <span class="n">total</span> <span class="o">+</span> <span class="n">e</span><span class="o">/</span><span class="m">2</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="kr">else</span> <span class="p">{</span> <span class="n">total</span> <span class="o">=</span> <span class="n">total</span> <span class="o">+</span> <span class="n">e</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">return</span><span class="p">(</span><span class="n">total</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">cppFunction</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;double soma_c(NumericVector v) {
</span></span></span><span class="line"><span class="cl"><span class="s">    double total = 0;
</span></span></span><span class="line"><span class="cl"><span class="s">    for (int i = 0; i &lt; v.size(); i++) {
</span></span></span><span class="line"><span class="cl"><span class="s">      if (v[i] &lt; 0) { total -= v[i]; }
</span></span></span><span class="line"><span class="cl"><span class="s">      else if (v[i] &gt; 0.75) { total += v[i]/2; }
</span></span></span><span class="line"><span class="cl"><span class="s">      else { total += v[i]; }
</span></span></span><span class="line"><span class="cl"><span class="s">    }
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    return(total);
</span></span></span><span class="line"><span class="cl"><span class="s">  }&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">v</span> <span class="o">&lt;-</span> <span class="nf">runif</span><span class="p">(</span><span class="m">100000</span><span class="p">,</span> <span class="m">-1</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">microbenchmark</span><span class="o">::</span><span class="nf">microbenchmark</span><span class="p">(</span><span class="nf">soma_r</span><span class="p">(</span><span class="n">v</span><span class="p">),</span> <span class="nf">soma_c</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Unit: milliseconds</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;       expr      min       lq     mean   median       uq       max neval</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  soma_r(v) 6.105048 6.436608 6.911819 6.718456 7.183266 11.610624   100</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;  soma_c(v) 1.045805 1.063956 1.161585 1.097920 1.210052  1.955702   100</span></span></span></code></pre></div><p><strong>Obs.</strong>: Os símbolos <code>+=</code> e <code>-=</code> são equivalentes a <code>a = a +/- b</code>, já o símbolo <code>++</code> é equivalente a <code>a = a + 1</code>.</p>
<h2 id="conclusão">Conclusão</h2>
<p>Com o pacote <code>Rcpp</code>, podemos rodar código em C++ de dentro do próprio R. Através dessa técnica conseguimos otimizar nosso código ou mesmo ter acesso a estruturas de dados complexas disponibilizadas pelo C++.</p>
<p>Para saber mais sobre o assunto, dê uma olhada no <a href="http://adv-r.had.co.nz/Rcpp.html">tutorial</a> escrito por Hadley Wickham no livro <em>Advanced R</em>. Também recomendo a própria <a href="http://www.rcpp.org/">página</a> do <code>Rcpp</code> e sua extensa <a href="http://gallery.rcpp.org/">galeria de exemplos</a>.</p>
<p>P.S.: Se você quiser o código completo deste tutorial, disponibilizei ele em um <a href="https://gist.github.com/clente/8d6c025a8e60319fdba63f247cef164a">Gist</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Encoberto com chance de cron</title>
      <link>https://lente.dev/posts/encoberto-cron/</link>
      <pubDate>Wed, 08 Nov 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/encoberto-cron/</guid>
      <description>Como agendar a execução de scripts R usando o pacote cronR e a incrível API meteorológica do DarkSky.</description>
      <content:encoded><![CDATA[<p>Nem sempre os dados que precisamos para uma análise podem ser encontrados em
uma base consolidada. Muitas vezes as informações que queremos não estão
imediatamente disponíveis e precisam ser coletadas com o tempo através de um
processo lento e monótono.</p>
<p>Imagine, por exemplo, que quiséssemos baixar os dados meteorológicos das
maiores cidades do mundo a cada 12 horas para uma análise sobre previsões do
tempo. Um programador desavisado talvez criasse alarmes em seu relógio e
para baixar as tabelas necessárias quando eles tocassem.</p>
<p>Mas isso não parece uma boa estratégia, certo?</p>
<h2 id="darksky">DarkSky</h2>
<p>Para demonstrar uma alternativa a este método, vamos usar um serviço de
previsões do tempo chamado <a href="https://darksky.net/">DarkSky</a>. Esta plataforma
ficou conhecida recentemente pela sua precisão incrível e pelo seu
<a href="https://play.google.com/store/apps/details?id=net.darksky.darksky&amp;hl=en">aplicativo</a>
extremamente bem feito, mas uma coisa que poucos sabem é que a DarkSky também
disponibiliza uma API para qualquer um interessado em dados meteorológicos.</p>
<p>Para a nossa sorte, o <a href="https://github.com/hrbrmstr">hrbrmstr</a> já criou uma
<a href="https://github.com/hrbrmstr/darksky">interface em R</a> para essa API que pode ser
instalada facilmente com o comando abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># install.packages(&#34;devtools&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">devtools</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;hrbrmstr/darksky&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Depois de instalado o pacote, vá para o <a href="https://darksky.net/dev">portal do desenvolvedor</a>
da DarkSky, crie uma conta e obtenha uma chave secreta para acessar a API.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">Sys.setenv</span><span class="p">(</span><span class="n">DARKSKY_API_KEY</span> <span class="o">=</span> <span class="s">&#34;SUA CHAVE SECRETA&#34;</span><span class="p">)</span></span></span></code></pre></div><h2 id="baixando-os-dados">Baixando os dados</h2>
<p>O primeiro passo da nossa análise é determinar as latitudes e longitudes das
maiores cidades cidades do mundo para que possamos pedir as previsões do tempo
destas coordenadas.</p>
<p>Com o pacote <code>maps</code> podemos fazer isso de uma maneira bastante simples:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">forecasts</span> <span class="o">&lt;-</span> <span class="n">maps</span><span class="o">::</span><span class="n">world.cities</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">filter</span><span class="p">(</span><span class="n">pop</span> <span class="o">&gt;</span> <span class="m">2000000</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">rename</span><span class="p">(</span><span class="n">country</span> <span class="o">=</span> <span class="n">country.etc</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">select</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">country</span><span class="p">,</span> <span class="n">lat</span><span class="p">,</span> <span class="n">long</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">dplyr</span><span class="o">::</span><span class="nf">mutate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">currently</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">hourly</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">daily</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">))</span></span></span></code></pre></div><p>No trecho de código acima pegamos todas as cidades com mais de 2 milhões de
habitantes (juntamente com suas localizações) da base <code>maps::world.cities</code>.
As últimas 4 linhas são uma preparação para a obtenção das previsões do tempo
que faremos logo a seguir:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">1</span><span class="o">:</span><span class="nf">nrow</span><span class="p">(</span><span class="n">forecasts</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">forecast</span> <span class="o">&lt;-</span> <span class="n">darksky</span><span class="o">::</span><span class="nf">get_current_forecast</span><span class="p">(</span><span class="n">forecasts</span><span class="o">$</span><span class="n">lat[i]</span><span class="p">,</span> <span class="n">forecasts</span><span class="o">$</span><span class="n">long[i]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">forecasts</span><span class="o">$</span><span class="n">currently[i]</span> <span class="o">&lt;-</span> <span class="n">forecast</span><span class="o">$</span><span class="n">currently</span> <span class="o">%&gt;%</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">%&gt;%</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="n">forecasts</span><span class="o">$</span><span class="n">hourly[i]</span> <span class="o">&lt;-</span> <span class="n">forecast</span><span class="o">$</span><span class="n">hourly</span> <span class="o">%&gt;%</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">%&gt;%</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="n">forecasts</span><span class="o">$</span><span class="n">daily[i]</span> <span class="o">&lt;-</span> <span class="n">forecast</span><span class="o">$</span><span class="n">daily</span> <span class="o">%&gt;%</span> <span class="n">dplyr</span><span class="o">::</span><span class="nf">as_tibble</span><span class="p">()</span> <span class="o">%&gt;%</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Na coluna <code>currently</code> guardamos o estado meteorológico atual da cidade, enquanto
em <code>hourly</code> e <code>daily</code> colocamos as previsões do tempo para as próximas 48 horas
e para os próximos 7 dias respectivamente. Agora só resta salvar isso tudo em um
arquivo RDS:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">file</span> <span class="o">&lt;-</span> <span class="n">lubridate</span><span class="o">::</span><span class="nf">now</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">lubridate</span><span class="o">::</span><span class="nf">ymd_hms</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.character</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span><span class="s">&#34;[-: ]&#34;</span><span class="p">,</span> <span class="s">&#34;_&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="s">&#34;.rds&#34;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">readr</span><span class="o">::</span><span class="nf">write_rds</span><span class="p">(</span><span class="n">forecasts</span><span class="p">,</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_c</span><span class="p">(</span><span class="s">&#34;DIRETÓRIO DOS ARQUIVOS&#34;</span><span class="p">,</span> <span class="n">file</span><span class="p">))</span></span></span></code></pre></div><h2 id="cronr">cronR</h2>
<p>Perceba que o script descrito na seção anterior não depende de nenhum input do
programador e pode ser rodado automaticamente. Agora só nos resta automatizar
essa execução, tarefa que realizaremos com o pacote <code>cronR</code>.</p>
<p>Esse pacote nos permite agendar a
execução de qualquer comando para que ela ocorra a cada tantos minutos/horas/dias/&hellip;
Certifique-se de que você está em uma máquina ou servidor que não será desligado,
<a href="https://en.wikipedia.org/wiki/Cron">verifique se o cron daemon está ativo</a> e
agende a execução do nosso script:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">cmd</span> <span class="o">&lt;-</span> <span class="n">cronR</span><span class="o">::</span><span class="nf">cron_rscript</span><span class="p">(</span><span class="s">&#34;CAMINHO PARA SCRIPT&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">cronR</span><span class="o">::</span><span class="nf">cron_add</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="s">&#34;daily&#34;</span><span class="p">,</span> <span class="s">&#34;12AM&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">cronR</span><span class="o">::</span><span class="nf">cron_add</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="s">&#34;daily&#34;</span><span class="p">,</span> <span class="s">&#34;12PM&#34;</span><span class="p">)</span></span></span></code></pre></div><p>E isso é tudo! No meu caso, agendei o script para executar diariamente às 00:00
e às 12:00, mas a frequência das chamadas fica a seu critério (lembrando apenas
que o plano gratuito da API do DarkSky só permite 1000 chamadas por dia). Para
saber mais sobre como mudar a frequência das execuções, consulte a
<a href="https://github.com/bnosac/cronR">documentação do cronR</a>.</p>
<h2 id="conclusão">Conclusão</h2>
<p>Como vimos, não é difícil agendar a execução de um script. A maior parte do
nosso trabalho é criar um código que funcione independentemente do programador
(por exemplo nomeando os arquivos gerados automaticamente), mas depois disso
é só chamar <code>cronR::cron_rscript()</code> e <code>cronR::cron_add()</code>.</p>
<p>No meu próximo post usarei os dados baixados com esse tutorial para uma análise
sobre previsões meteorológicas, então fique ligado na parte dois!</p>
<p>P.S.: Se você quiser o código completo do meu arquivo <code>get_forecasts.R</code>,
disponibilizei ele como <a href="https://gist.github.com/clente/997f603f05883fcda573d96e310dad69">um Gist</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A magia do purrr</title>
      <link>https://lente.dev/posts/magica-purrr/</link>
      <pubDate>Fri, 18 Aug 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/magica-purrr/</guid>
      <description>Como usar o purrr (um pacote de R) para lidar com iterações de uma forma muito mais direta e elegante.</description>
      <content:encoded><![CDATA[<p>Você já ouviu falar sobre um pacote de R chamado <code>purrr</code>? Ele é descrito como um <em>toolkit</em>
de programação funcional para a linguagem R e permite que façamos coisas honestamente
incríveis. Se você nunca ouviu falar sobre o <code>purrr</code> ou mesmo se já ouviu falar mas não
sabe de todo o seu potencial, esse post é feito para você.</p>
<h2 id="perdão-pela-honestidade">Perdão pela honestidade</h2>
<p>Se você quisesse tornar o R mais conciso, o que você mudaria nele? Uma boa primeira
tentativa talvez envolvesse simplificar a &ldquo;composição de funções&rdquo; (o ato de
aplicar uma função ao resultado de outra). Dê uma olhada nesse exemplo horrível:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">car_data</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">  <span class="nf">transform</span><span class="p">(</span><span class="nf">aggregate</span><span class="p">(</span><span class="n">. </span><span class="o">~</span> <span class="n">cyl</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                      <span class="n">data</span> <span class="o">=</span> <span class="nf">subset</span><span class="p">(</span><span class="n">mtcars</span><span class="p">,</span> <span class="n">hp</span> <span class="o">&gt;</span> <span class="m">100</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                      <span class="n">FUN</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="nf">round</span><span class="p">(</span><span class="nf">mean</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="m">2</span><span class="p">))),</span>
</span></span><span class="line"><span class="cl">            <span class="n">kpl</span> <span class="o">=</span> <span class="n">mpg</span><span class="o">*</span><span class="m">0.4251</span><span class="p">)</span></span></span></code></pre></div><p>Se não quisermos salvar resultados intermediários, compor diversas funções passa a ser
super importante. Mas a estratégia mostrada acima faz com que seja muito difícil entender
o que está acontecendo e em que ordem (para os nerds lendo isso, é o equivalente de
escrever


<math display="inline"><mrow><mi>g</mi><mo form="prefix" stretchy="false">(</mo><mi>f</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo><mo form="postfix" stretchy="false">)</mo></mrow></math>
 ao invés de


<math display="inline"><mrow><mi>f</mi><mo>∘</mo><mi>g</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo></mrow></math>
). Em R, a solução para esse problema vem
na forma do &ldquo;<em>pipe</em>&rdquo;, um operador que nos permite colocar a primeira função antes da segunda
e não dentro dela:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">car_data</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">  <span class="n">mtcars</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">subset</span><span class="p">(</span><span class="n">hp</span> <span class="o">&gt;</span> <span class="m">100</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">aggregate</span><span class="p">(</span><span class="n">. </span><span class="o">~</span> <span class="n">cyl</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">.,</span> <span class="n">FUN</span> <span class="o">=</span> <span class="n">. </span><span class="o">%&gt;%</span> <span class="n">mean</span> <span class="o">%&gt;%</span> <span class="nf">round</span><span class="p">(</span><span class="m">2</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">transform</span><span class="p">(</span><span class="n">kpl</span> <span class="o">=</span> <span class="n">mpg</span> <span class="o">%&gt;%</span> <span class="nf">multiply_by</span><span class="p">(</span><span class="m">0.4251</span><span class="p">))</span></span></span></code></pre></div><p>Mas o que mais você mudaria no R? Bem, o próximo lugar que evidentemente precisa de
uma melhoria são só laços&hellip;</p>
<h2 id="listas-de-listas">Listas de listas</h2>
<p>Antes de começarmos a demonstração, você vai precisar de alguns pacotes. Instale-os
rodando o código abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s">&#34;devtools&#34;</span><span class="p">,</span> <span class="s">&#34;purrrr&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">devtools</span><span class="o">::</span><span class="nf">install_github</span><span class="p">(</span><span class="s">&#34;jennybc/repurrrsive&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">purrr</span><span class="p">)</span></span></span></code></pre></div><p>Agora que temos tudo pronto, vamos conhecer melhor a estrela desse tutorial! <code>gh_repos</code>
é uma lista multi-nível gigantesca que pode assustar até os programadores de R mais
experientes. Eu vou renomear <code>gh_repos</code> para <code>ghr</code> por simplicidade:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ghr</span> <span class="o">&lt;-</span> <span class="n">repurrrsive</span><span class="o">::</span><span class="n">gh_repos</span></span></span></code></pre></div><p>Felizmente a sua estrutura é simples o suficiente para que possamos usá-la para
propósitos educacionais. O primeiro nível de <code>ghr</code> é composto por 6 listas, cada uma
representando um <strong>usuário</strong> do GitHub. Cada uma destas listas é feita de mais ou menos
30 listas menores representando os <strong>repositórios</strong> daquele usuário. Cada repositório
tem mais de 60 campos com <strong>informações</strong> sobre o repo; um destes campos também é uma
lista e contém <strong>dados de login</strong> pertencentes ao dono do repo.</p>
<figure><img src="https://lente.dev/posts/purrr-magic/ghr_pt.webp"/>
</figure>
<p>Eu sei que isso não parece muito fácil de entender, mas vamos revisar a estrutura
algumas vezes ainda. Antes de tudo vamos só refrescar as nossas habilidades com listas
e descobrir quantos repositórios o primeiro usuário em <code>ghr</code> tem:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">length</span><span class="p">(</span><span class="n">ghr[[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span></span></span></code></pre></div><p>Nesse pequeno comando estamos selecionando o primeiro elemento do primeiro nível da lista
(<code>ghr[[1]]</code>) ou, em outras palavras, estamos escolhendo o primeiro usuário. Ao aplicar
<code>length()</code> neste usuário, podemos ver quantos elementos ele(a) tem, resultando no número
de repositórios pertencentes a ele(a). De forma geral, se quiséssemos ver quantos campos
de informação tem o terceiro repo deste usuário (ou o comprimento do terceiro elemento
do segundo nível associado ao primeiro elemento do primeiro nível), poderíamos rodar
<code>length(ghr[[1]][[3]])</code>.</p>
<h2 id="laços-de-uma-linha">Laços de uma linha</h2>
<p>Agora que você se lembra de como listas funcionam em R, um óbvio incremento de dificuldade
é descobrir quantos repositórios cada usuário tem. Isso pode ser resolvido com o bom e
velho laço <code>for</code>, aplicando <code>length()</code> a cada elemento do primeiro nível de <code>ghr</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">lengths</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="nf">seq_along</span><span class="p">(</span><span class="n">ghr</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">lengths</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="n">lengths</span><span class="p">,</span> <span class="nf">length</span><span class="p">(</span><span class="n">ghr[[i]]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">lengths</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30 30 30 26 30 30</span></span></span></code></pre></div><p>Mas vamos com calma, tem que existir um jeito mais fácil! Só estamos iterando em uma lista,
por que precisamos de <code>i</code>, <code>c()</code>, <code>seq_along()</code>, ou mesmo <code>lengths</code>? É aqui que o <code>map()</code>
entra em jogo, o carro chefe do pacote <code>purrr</code>. <code>map()</code> é uma abstração de laços, permitindo
que iteremos nos elementos de uma lista e não em alguma variável auxiliar. Em outras
palavras ele aplica uma função em todo elemento de uma lista.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[4]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 26</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[5]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[6]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30</span></span></span></code></pre></div><p>Bem, usamos menos linhas de código, mas o que está acontecendo com essa saída? <code>map()</code> é
uma função muito genérica, então ela sempre retorna listas (assim ela não precisa se
preocupar com o tipo da saída). Mas <code>map()</code> tem várias funções irmãs, <code>map_xxx()</code>
(<code>map_dbl()</code>, <code>map_chr()</code>, <code>map_lgl()</code>, &hellip;), que são capazes de &ldquo;nivelar&rdquo; a saída
se você já souber que tipo ela terá. No nosso caso queremos um vetor de <em>doubles</em>,
então usamos <code>map_dbl()</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30 30 30 26 30 30</span></span></span></code></pre></div><p>Você viu isso?! São apenas 21 caracteres e eles fizeram a mesma coisa que aquele laço
horrível lá em cima!</p>
<h2 id="fórmulas-e-funções">Fórmulas e funções</h2>
<p>Agora que você já conheceu os princípios fundamentais do <code>purrr</code>, eu vou lhe
apresentar às funções anônimas, outra funcionalidade interessantíssima do pacote.
Elas são funções que podemos definir dentro de um <code>map()</code> sem ter que nomeá-las,
aparecendo em duas formas: fórmulas e funções.</p>
<p>Fórmulas são antecedidas por um til e você não pode controlar o nome de seus
argumentos. Funções por outro lado são, bem, funções normais do R. Primeiramente
vamos ver como fórmulas funcionam:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map_dbl</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">length</span><span class="p">(</span><span class="n">.x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 30 30 30 26 30 30</span></span></span></code></pre></div><p>Fórmulas nos permitem passar argumentos para a função sendo mapeada. Lembre-se
de como estamos tirando o comprimento de cada sub-lista de <code>ghr</code>? Se usarmos
a notação-til podemos explicitamente acessar aquele elemento e colocá-lo onde
quisermos dentro da chamada da função, mas o seu nome será <code>.x</code> independentemente
de qualquer outra coisa.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="o">~</span><span class="nf">runif</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="n">max</span> <span class="o">=</span> <span class="n">.x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 0.2512402 0.4499058</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 1.767479 1.600513</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 2.367293 1.263795</span></span></span></code></pre></div><p>No exemplo acima temos que usar a notação-til porque, se não tivéssemos, o vetor
<code>1:3</code> acabaria sendo usado como o primeiro argumento de <code>runif()</code>. E falando em
argumentos, <code>map()</code> convenientemente permite que você envie qualquer outro
argumento fixo no final da chamada (note como desta vez <code>1:3</code> é usado
automaticamente como o primeiro argumento).</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="n">runif</span><span class="p">,</span> <span class="n">min</span> <span class="o">=</span> <span class="m">3</span><span class="p">,</span> <span class="n">max</span> <span class="o">=</span> <span class="m">6</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 3.902211</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 4.511896 4.405196</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 5.498137 3.940454 5.413348</span></span></span></code></pre></div><p>E por último mas não menos importante, funções. Elas são muito parecidas com
fórmulas, entretanto aqui você pode nomear os argumentos como quiser (a
desvantagem é que você tem que definir a função de forma bastante prolixa):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="kr">function</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">{</span> <span class="nf">runif</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">min</span> <span class="o">=</span> <span class="m">3</span><span class="p">,</span> <span class="n">max</span> <span class="o">=</span> <span class="m">6</span><span class="p">)</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 4.54061</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 3.557612 4.022569</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 3.369300 4.109919 4.095583</span></span></span></code></pre></div><h2 id="maps-e-maps">Maps e maps</h2>
<p>Como você já deve ter percebido, também é possível chamar uma <code>map()</code> dentro
da outra! Isso é muito útil quando queremos acessar níveis mais profundos de
uma lista (como quando falamos sobre <code>length(ghr[[1]][[3]])</code>). Vamos ver quantos
campos de informação tem cada repo de cada usuário:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="n">length</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]][[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]][[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]][[3]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]][[4]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map_dbl</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="n">length</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [20] 68 68 68 68 68 68 68 68 68 68 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [20] 68 68 68 68 68 68 68 68 68 68 68</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span></span></span></code></pre></div><p>O primeiro comando acima devolve uma lista de listas muito longas, mas isso
se deve somente ao fato de que o <code>map()</code> mais interior retorna uma lista
para cada repo e depois o <code>map()</code> mais de fora embrulha tudo aquilo em outra
lista. Para uma saída mais inteligente, usar <code>map_dbl()</code> na chamada mais
interna nos permite devolver um único vetor para cada usuário.</p>
<p>No entanto, esse campos contém outras informações preciosas. Até agora nossa lista
permaneceu completamente sem nomes, o que significa que cada lista de usuário
e cada lista de repo não estão marcadas com os nomes dos usuários e repos. Vamos
ver se podemos encontrar os nomes dos usuários no campo <code>login</code> da lista <code>$owner</code>
de cada repo (note o uso de <code>map_chr()</code>; esse é o equivalente de <code>map_dbl()</code>
para caracteres):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="kr">function</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">map_chr</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[1]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] &#34;gaborcsardi&#34; &#34;gaborcsardi&#34; &#34;gaborcsardi&#34; &#34;gaborcsardi&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [5] &#34;gaborcsardi&#34; &#34;gaborcsardi&#34; &#34;gaborcsardi&#34; &#34;gaborcsardi&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [[2]]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [6] &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34; &#34;jennybc&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="kr">function</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">user</span> <span class="o">%&gt;%</span> <span class="nf">map_chr</span><span class="p">(</span><span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span></span></span></code></pre></div><p>Todos os 3 comandos devolvem exatamente a mesma coisa, mas o primeiro é o
mais fácil de entender. Para cada autor, iteramos em seus repos e acessamos
o elemento <code>$owner$login</code>. O segundo nos mostra que é possível mapear um <em>pipe</em>.
O terceiro por sua vez condensa tudo ao máximo (note como usamos <code>.x</code> duas
vezes; a primeira vez vem do <code>map()</code> e representa cada usuário, enquanto a
segunda vem do <code>map_chr()</code> e representa cada repo).</p>
<p>No entanto, todos todos os comandos sofrem de repetição na saída dado que
estamos fazendo a mesma coisa para cada repo disponível. Já que só precisamos
dessa informação uma vez para cada usuário, podemos usar o bom e velho <code>[1]</code>
para pegar apenas o primeiro elemento do vetor retornado por <code>map_chr()</code>
e depois usar outro <code>map_chr()</code> para que não precisemos lidar com listas
estranhas:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">map_chr</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span><span class="n">[1]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] &#34;gaborcsardi&#34; &#34;jennybc&#34;     &#34;jtleek&#34;      &#34;juliasilge&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [5] &#34;leeper&#34;      &#34;masalmon&#34;</span></span></span></code></pre></div><h2 id="pipes-e-maps">Pipes e maps</h2>
<p>Na seção acima usamos <code>map()</code>s com <em>pipes</em>, e agora vamos usar <em>pipes</em>
com <code>map()</code>s. Isso deveria ser bastante lógico dado o último trecho
de código, mas vamos usar o <code>map()</code> para pegar o login dos usuários,
usar <code>set_names()</code> para dar nomes aos usuários de acordo com seus
logins e por fim usar <code>pluck()</code> para selecionar a lista de repositórios
de &ldquo;jennybc&rdquo; (note o ponto em <code>set_names()</code>; ele representa o resultado
vindo da linha cima, estamos usando ele como o segundo argumento da
função):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ghr</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">map_chr</span><span class="p">(</span><span class="o">~</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span><span class="n">[1]</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">set_names</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="n">.)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pluck</span><span class="p">(</span><span class="s">&#34;jennybc&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span></span></span></code></pre></div><p>A saída desse comando foi omitida, mas usando <code>pluck()</code> selecionamos
apenas o elemento de <code>ghr</code> chamado &ldquo;jennybc&rdquo; (essa função trabalha
exatamente como <code>[[]]</code>, então poderíamos ter usado <code>2</code> já que a lista
de Jenny é a segunda do primeiro nível).</p>
<h2 id="e-assim-por-diante">E assim por diante&hellip;</h2>
<p>Agora que sabemos nomear o primeiro nível da estrutura, que tal fazermos
o mesmo para os repos? Para isso precisamos ir um nível mais fundo
e colocar nomes lá também:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ghr</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">map</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">user</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">      <span class="nf">set_names</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="n">.,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">name</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pluck</span><span class="p">(</span><span class="s">&#34;jennybc&#34;</span><span class="p">,</span> <span class="s">&#34;eigencoder&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ghr</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">set_names</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="nf">map</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">name</span><span class="p">)))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pluck</span><span class="p">(</span><span class="s">&#34;jennybc&#34;</span><span class="p">,</span> <span class="s">&#34;eigencoder&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span></span></span></code></pre></div><p>As duas sequencias devolvem a mesma coisa (omitida), mas a segunda é
muito mais concisa. Aqui estamos iterando nos usuários, nomeando cada
repo de acordo com o elemento <code>$name</code> de cada um e por fim selecionando
o repositório <code>eigencoder</code> de Jenny (que seria equivalente a <code>[[2]][[30]]</code>).</p>
<h2 id="dois-coelhos">Dois coelhos</h2>
<p>O legal de programar é tentar escrever a mesma coisa no mínimo de caracteres
possível (tarefa apelidada de <em>code golf</em>). Antes de nomearmos tanto usuários
e repos, vamos deixar o processo de nomear usuários seja um pouco mais enxuto:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">set_names</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="nf">map_chr</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map_chr</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span><span class="n">[1]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nf">set_names</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="nf">map</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">)</span><span class="n">[[1]]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nf">set_names</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="nf">map</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="o">~</span><span class="n">.x[[1]]</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">))</span></span></span></code></pre></div><p>Todos os 3 comandos fazem a mesma coisa, sendo que já vimos o primeiro antes.
O segundo comando aproveita-se do fato de que <code>set_names()</code> não precisa
receber um vetor como argumento, uma lista também funciona. O terceiro
inverte a ideia de pegar o login de todos os repos e depois selecionar o primeiro
pegando o login apenas do primeiro repo.</p>
<p>Agora que temos a forma mais curta possível de nomear os elementos principais
de <code>ghr</code>, aqui está o que eu chamo de dois coelhos em uma cajadada:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ghr</span> <span class="o">&lt;-</span> <span class="n">ghr</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">set_names</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="n">.,</span> <span class="o">~</span><span class="n">.x[[1]]</span><span class="o">$</span><span class="n">owner</span><span class="o">$</span><span class="n">login</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">map</span><span class="p">(</span><span class="o">~</span><span class="nf">set_names</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="nf">map</span><span class="p">(</span><span class="n">.x</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">name</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="nf">names</span><span class="p">(</span><span class="n">ghr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] &#34;gaborcsardi&#34; &#34;jennybc&#34;     &#34;jtleek&#34;      &#34;juliasilge&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [5] &#34;leeper&#34;      &#34;masalmon&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="nf">names</span><span class="p">(</span><span class="n">ghr</span><span class="o">$</span><span class="n">jennybc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [1] &#34;2013-11_sfu&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [2] &#34;2014-01-27-miami&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [3] &#34;2014-05-12-ubc&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span></span></span></code></pre></div><h2 id="e-falando-em-dois">E falando em &ldquo;dois&rdquo;&hellip;</h2>
<p>Para finalizar esse tutorial, vou criar uma função simples que retorna
o número de estrelas que cada usuário tem. Nessa tarefa temos que iterar
em dois objetos: <code>ghr</code> e os nomes de seus usuários.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">about</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">stars</span> <span class="o">&lt;-</span> <span class="nf">map_dbl</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="o">~</span><span class="n">.x</span><span class="o">$</span><span class="n">stargazers_count</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">sum</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="nf">message</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="s">&#34; has &#34;</span><span class="p">,</span> <span class="n">stars</span><span class="p">,</span> <span class="s">&#34; stars!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">map2</span><span class="p">(</span><span class="n">ghr</span><span class="p">,</span> <span class="nf">names</span><span class="p">(</span><span class="n">ghr</span><span class="p">),</span> <span class="n">about</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># gaborcsardi has 289 stars!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># jennybc has 190 stars!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># jtleek has 4910 stars!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># juliasilge has 308 stars!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># leeper has 66 stars!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># masalmon has 47 stars!</span></span></span></code></pre></div><p>Em <code>about()</code> pegamos a soma da contagem de <em>star gazers</em> de cara repo de um
usuário (usando <code>map_dbl()</code>, claro) e depois soltamos a mensagem com o nome.
Para fazer isso para cada usuário de <code>ghr</code>, usamos a prima mais próxima de
<code>map()</code>: <code>map2()</code>.</p>
<p>Essa função é análoga a <code>map()</code>, mas itera em duas listas ao invés de somente
usa (note que para fórmulas usamos <code>.x</code> no lugar dos elementos da primeira lista
e <code>.y</code> no lugar dos elementos da segunda). E agora que você já entende os
membros mais importantes da família <code>map()</code>, aqui está uma lista de todos os
outros que você já pode começar a usar:</p>
<ul>
<li><code>map2_xxx()</code> (análoga a <code>map_xxx()</code>)</li>
<li><code>pmap()</code> (com a qual você pode iterar em quantos elementos forem necessários)</li>
<li><code>lmap()</code> (para mapear com funções que recebem e retornam listas)</li>
<li><code>imap()</code> (para iterar em uma lista e seus nomes, assim como acabamos de fazer)</li>
<li><code>map_at()/map_if()</code> (funções que permitem com que você filtre quais elementos
serão mapeados)</li>
</ul>
<h2 id="palavras-finais">Palavras finais</h2>
<p>Esse não foi um post pequeno, mas eu sinto que não poderia ter feito ele em menos
palavras. Mapeamento é um conceito complicado e demorou muito tempo para que eu
entendesse o pouco que eu sei.</p>
<p>O pacote <code>purrr</code> é realmente uma ferramenta incrível (na minha opinião, a mais
conveniente e bonita da linguagem R) e é justo dizer que a <code>map()</code> é grande
parte do motivo&hellip; Mas ela não é a única família de funções no pacote!</p>
<p>No próximo post falaremos sobre algumas outras funções do <code>purrr</code>:
<code>reduce()</code>, <code>flatten()</code>, <code>invoke()</code>, <code>modify()</code>, <code>possibly()</code> e <code>keep()</code>.
Enquanto isso, dê uma olhada no <a href="https://github.com/clente">meu github</a>,
no de <a href="https://github.com/jennybc">Jennifer Bryan</a> (autora do <code>repurrrsive</code>)
e no de <a href="https://github.com/hadley">Hadley Wickham</a> (autor do <code>purrr</code> e outros
pacotes incríveis de R).</p>
]]></content:encoded>
    </item>
    <item>
      <title>A fixação de Colbert</title>
      <link>https://lente.dev/posts/trump-colbert/</link>
      <pubDate>Thu, 22 Jun 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/trump-colbert/</guid>
      <description>Uma análise dos termos mais frequentes utilizados por Stephen Colbert no The Late Show, e sua fixação com Trump.</description>
      <content:encoded><![CDATA[<p>Stephen Colbert é um comediante americano e apresentador do programa de TV
<em>The Late Show</em>. Em seus quase 2 anos apresentando o programa, Colbert consolidou
um estilo extremamente próprio que eu só consigo descrever muito vagamente; seria
algo como as entrevistas de Jô Soares + os stand ups de Fábio Porchat + o jornalismo
de Willian Bonner.</p>
<p>Se você ainda não o conhece e não pretende mudar isso, eu vou te dar o resumo
mais curto possível da sua rotina: ele tira sarro do Donald Trump.</p>
<p>Ele é um esquerdista bastante vocal e não tem medo de fazer piada com a pessoa
que ele enxerga como um maluco liderando seu país. Concorde ou não com ele, você
precisa admitir que ele é bem engraçado&hellip;</p>
<p>Mas mesmo sabendo que Colbert é conhecido por fazer piada com o presidente dos EUA,
assistindo a seu programa no <a href="https://www.youtube.com/channel/UCMtFAi84ehTSYSE9XoHefig">YouTube</a>
comecei a achar que talvez ele falasse um pouco demais sobre Trump. No fim eu não
consegui me segurar e tive que fazer a pergunta: quanto, de fato, Stephen Colbert
fala sobre Donald Trump?</p>
<p>Resposta curta: muito, tipo, <em>muito</em>.</p>
<p>Resposta longa:</p>
<h2 id="quanto-exatamente">Quanto exatamente?</h2>
<p>Na minha busca para encontrar a resposta, o primeiro passo era coletar as transcrições
do seu programa. Eu criei <a href="https://gist.github.com/clente/84d72770db65667add6fe8531408c0af">um script</a>
que baixou a legenda de mais ou menos um terço (990 para ser preciso) dos vídeos
de seu canal do YouTube e decidi que essa era uma amostra grande o suficiente.</p>
<p>O segundo passo era limpar as legendas. Elas estavam cheias de símbolos (como notas
musicais), indicadores de quem estava falando e ações da platéia (palmas, gritos, &hellip;)
que tinham que ser removidos para que ficássemos apenas com a informação relevante.
Outro passo importante na mineração de texto é se livrar das palavras vazias (coisas
como &ldquo;o&rdquo;, &ldquo;a&rdquo;, &ldquo;um&rdquo;, etc.), então eu fui em frente e fiz isso também.</p>
<p>Depois que acabei os procedimentos descritos acima, eu ainda tinha mais de 260.000
palavras de áudio transcrito! E ainda que isso tudo não é 100% Colbert falando,
é o suficiente para que tenhamos uma boa estimativa do conteúdo de seu programa.</p>
<p>A primeira coisa que eu queria saber era quais palavras ele mais fala. Dê uma
olhada na vencedora&hellip;</p>
<figure><img src="https://lente.dev/posts/trump-colbert/top_terms_pt.webp"/>
</figure>
<p>É isso mesmo, excluindo palavras vazias, o termo mais usado no seu programa foi
&ldquo;Trump&rdquo;. Ele apareceu nas legendas 3252 vezes, chegando a 1,2% de todas as palavras
não-vazias. Se considerarmos a nossa amostra como representativa dos mais de 2600
vídeos em seu canal do YouTube e assumirmos que metade de todo programa é disponibilizado
online e que ele é a pessoa falando 3/4 do tempo, concluímos que <strong>Stephen Colbert
falou “Trump” mais de 12.000 vezes em seu programa!</strong></p>
<p>Mas só porque ele fala a palavra &ldquo;Trump&rdquo; tantas vezes, isso não quer necessariamente
dizer que ele fala muito <em>sobre</em> o Trump. Para descobrir se todas essas 12.000
citações são simplesmente referências sem contexto, eu tive que usar uma técnica mais
complexa chamada modelagem de tópico.</p>
<h2 id="mas-de-verdade">Mas de verdade&hellip;</h2>
<p>De acordo com a <a href="https://en.wikipedia.org/wiki/Topic_model">Wikipedia</a>, um modelo
de tópico é &ldquo;um tipo de modelo estatístico usado para descobrir os &rsquo;tópicos&rsquo; abstratos
que ocorrem em uma coleção de documentos&rdquo;. O modelo que escolhi se chama
<a href="https://en.wikipedia.org/wiki/Latent_Dirichlet_allocation">Alocação Latente de Dirichlet (LDA)</a>
e o ajustei para que ele procurasse 2 tópicos no nosso conjunto de textos.</p>
<p>Como esperado, o modelo foi capaz de dividir as palavras de Colbert em dois temas
principais: entrevistas e política. Podemos ver isso dando uma olhada nas palavras
que o modelo considerou mais características de cada tópico.</p>
<figure><img src="https://lente.dev/posts/trump-colbert/log_ratio_pt.webp"/>
</figure>
<p>De forma simples, a &ldquo;razão dos logs&rdquo; na abscissa de cada gráfico indica se um termo
aparece mais em um tópico do que no outro; quanto mais negativo o valor, mais o
termo apareceu no tópico A e não no tópico B e vice-versa.</p>
<p>O tópico A é claramente sobre política: outros termos desse tópico não mostrados
no gráfico são &ldquo;campaign&rdquo;, &ldquo;tax&rdquo; e &ldquo;republicans&rdquo;. O tópico B por outro lado é
mais representado pelas conversas de Colbert com seus convidados: outros termos
incluem &ldquo;comedy&rdquo;, &ldquo;song&rdquo; e &ldquo;band&rdquo;.</p>
<p>Mas você pode estar se perguntando para onde foi a palavra &ldquo;Trump&rdquo;&hellip; Ela não
aparece nesses gráficos porque não existe um tópico em que ela apareça muito mais
que no outro! Com isso, podemos concluir que, não somente Colbert fala muito a
palavra &ldquo;Trump&rdquo;, mas também que o presidente dos EUA é um assunto constante no
programa mesmo quando consideramos apenas as conversas com convidados.</p>
<p>Isso é Trump o suficiente para você?</p>
<h2 id="epílogo">Epílogo</h2>
<p>A análise nesse post foi conduzida inteiramente em R. A limpeza e modelagem foram
realizadas com a ajuda dos pacotes <code>tidytext</code> e <code>topicmodels</code>. Para criar o
procedimento analítico, eu segui os exemplos de <a href="http://tidytextmining.com">Text Mining with R</a>
passo-a-passo. Meu <a href="https://gist.github.com/clente/84d72770db65667add6fe8531408c0af">script</a>
baixa todas as legendas de <a href="http://ccSubs.com">ccSubs</a>. E, por último mas não menos
importante, se você quiser reproduzir as análises por conta própria, o código
que utilizei está disponível como um <a href="https://gist.github.com/clente/da6434ce9de312fedd848d813df39303">Gist</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Anotando aulas de exatas</title>
      <link>https://lente.dev/posts/tomando-notas/</link>
      <pubDate>Tue, 13 Jun 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/tomando-notas/</guid>
      <description>Meu jeito favorito de tomar notas em aulas de exatas com o meu computador usando tanto Markdown quanto LaTeX no Atom.</description>
      <content:encoded><![CDATA[<p>Meu maior problema na faculdade (fora passar nas matérias) sempre foi anotar as aulas. Eu sou o tipo de pessoa que gosta anotar absolutamente tudo que o(a) professor(a) fala para o caso de algum detalhe obscuro de uma aula perdida ser cobrado na prova.</p>
<p>Em pouco tempo percebi que anotar tudo em papel era impraticável. Fora o cansaço de copiar lousas intermináveis, muitos professores são desorganizados demais para que seja possível anotar linearmente o que está sendo dito em aula. Que atire a primeira pedra aquele aluno que nunca desistiu de anotar uma aula ao perceber que o(a) professor(a) havia cometido um erro duas lousas atrás.</p>
<h2 id="possíveis-soluções">Possíveis soluções</h2>
<p>A primeira coisa que todo aluno pensa nesses momentos de raiva é em fazer suas anotações no computador (caso ele(a) o tenha). Por um segundo essa pode parecer a solução perfeita, mas ela nem sempre funciona; se você é um aluno de humanas pode até ser que um editor de texto comum como Word ou Pages funcione para anotar as suas aulas, mas se você tiver que anotar ao menos uma equação esses programas já se tornam uma solução menos que ideal.</p>
<p>Como sou aluno de Ciência da Computação ainda tenho um problema a mais: anotar código. Falando com meus amigos, chegamos à conclusão de que anotar as nossas aulas em <a href="https://pt.wikipedia.org/wiki/LaTeX">LaTeX</a> talvez fosse a única saída. Dito isso, sugiro que o leitor tente anotar pelo menos uma aula na vida em LaTeX para entender porque descarto essa ideia…</p>
<p>Dessa forma cheguei a três critérios que qualquer solução deveria atender para ser considerada ótima:</p>
<ul>
<li>Praticidade (descartamos dessa forma anotar as aulas em papel)</li>
<li>Facilidade de anotar equações e código (descartamos editores de texto comuns)</li>
<li>Velocidade na hora de escrever (descartamos LaTeX)</li>
</ul>
<p>Não ia ser fácil…</p>
<h2 id="uma-luz-no-fim-do-túnel">Uma luz no fim do túnel</h2>
<p>Depois de muito tempo procurando uma solução ideal, acabei a encontrando debaixo do meu nariz. Para programar eu já usava há alguns anos um editor de código chamado <a href="https://atom.io">Atom</a>, mas o que eu ainda não sabia é que esse editor é extremamente customizável, permitindo que o usuário baixe plugins cuja função é estender a funcionalidade do editor.</p>
<p>Um desses plugins se chama <a href="https://atom.io/packages/markdown-preview-plus">Markdown Preview Plus</a> (MMP) e ele foi a luz no fim do túnel que era o meu caderno de anotações. Ele junta duas tecnologias opostas de forma que temos o melhor dois dois mundos! Para texto e código ele nos permite usar <a href="https://pt.wikipedia.org/wiki/Markdown">Markdown</a>, enquanto para equações ele nos permite usar LaTeX (mas sem a parte de formatação de texto, que tornava qualquer solução LaTeX-pura lenta e ineficiente).</p>
<p>Ler essas duas palavras juntas na mesma frase pode ser intimidador, mas acredite em mim quando digo que ela salvou minha vida. Não posso dizer que não existe uma curva de aprendizado, porém a recompensa é muito maior que os poucos dias que você perderá aprendendo Markdown ou LaTeX.</p>
<h2 id="como-instalar-o-mmp">Como instalar o MMP</h2>
<p>Para que tudo isso funcione, você precisa primeiro instalar o Atom. Feito isso, navegue até o menu do editor e procure a aba denominada <strong>Install</strong> e instale também o Markdown Preview Plus. O passo final é ir até a aba <strong>Packages</strong>, procurar o MMP e, em suas configurações, habilitar a opção <strong>Enable Math Rendering By Default</strong>.</p>
<p>Crie um arquivo <code>.md</code>  e pressione a combinação <code>ctrl + shift + M</code> para ativar o <em>preview</em> do Markdown. Agora é só escrever em Markdown e colocar qualquer código LaTeX entre dois cifrões para renderizar qualquer fórmula matemática!</p>
<p>E em teoria isso é tudo 😊 Essa solução une a praticidade do computador, as funcionalidades do LaTeX e a velocidade do Markdown de forma que eu nunca imaginei que fosse possível. Mas para aqueles que não estão familiarizados com Markdown ou LaTeX, ainda resta o desafio de aprendê-los…</p>
<h2 id="exemplos">Exemplos</h2>
<p>Para saber mais sobre Markdown, sugiro o tutorial criado pelo GitHub: <a href="https://guides.github.com/features/mastering-markdown/">Mastering Markdown</a>. Já LaTeX não precisa exatamente de um tutorial no nosso caso, mas sim de uma cola: <a href="https://en.wikibooks.org/wiki/LaTeX/Mathematics">LaTeX/Mathematics</a>.</p>
<p>Para fins ilustrativos, veja o texto escrito abaixo:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-md" data-lang="md"><span class="line"><span class="cl"><span class="gh"># Matéria Importante
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="gu">## Aula de hoje
</span></span></span><span class="line"><span class="cl"><span class="gu"></span>
</span></span><span class="line"><span class="cl">Com Markdown podemos criar
</span></span><span class="line"><span class="cl"><span class="k">-</span> *Uma lista*
</span></span><span class="line"><span class="cl"><span class="k">-</span> <span class="sb">`Com itens`</span>
</span></span><span class="line"><span class="cl"><span class="k">-</span> **Em diversas**
</span></span><span class="line"><span class="cl"><span class="k">-</span> formatações
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Seja $X$ o número de comparações executadas na linha 4 da função
</span></span><span class="line"><span class="cl"><span class="sb">`particione()`</span>. Observe que $X$ é uma variável aleatória.
</span></span><span class="line"><span class="cl">Tome $X_{ab}$ a variável aleatória binária com interpretação
</span></span><span class="line"><span class="cl">$X_{ab} = 1$ se e somente se $a$ e $b$ são comparados na linha 4.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Algo bem complicado (e sem sentido):
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$m = \begin{cases}
</span></span><span class="line"><span class="cl">    m[i, j] = n + \sum_{k = 0}^{\lfloor \lg n \rfloor} 2^k = n +
</span></span><span class="line"><span class="cl">    2^{\lfloor \lg n \rfloor} - 1 ≤ n + 2.2^{\lg n} <span class="err">&amp;</span> i = j \\
</span></span><span class="line"><span class="cl">    m[i, j] = min_{\ i ≤ k ≤ j-1}\{ m[i, k] + m[k+1, j] +
</span></span><span class="line"><span class="cl">    p_{i-1} \ p_k \ p_j\} <span class="err">&amp;</span> i \not = j
</span></span><span class="line"><span class="cl">\end{cases}$</span></span></code></pre></div><p>Esse é o seu resultado quando renderizado pelo MMP:</p>
<figure><img src="https://lente.dev/posts/note-taking/atom.webp"/>
</figure>
<h2 id="funcionalidades-bônus">Funcionalidades bônus</h2>
<p>Se você quiser maximizar a velocidade com que você faz as anotações, sugiro tirar vantagem de <em>snippets</em> do Atom. Os que eu uso estão disponíveis em um <a href="https://gist.github.com/ctente/cfabebcc7555286f491aa7ce3ac700fe">Gist</a>.</p>
<p>Para exportar suas anotações como PDF, clique com o botão direito no <em>preview</em> e selecione <strong>Save as HTML</strong>. Esse arquivo pode ser aberto no seu navegador e assim ser salvo como PDF com <code>cmd/ctrl + P</code>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fa·vo·ri·tis·mo, s.</title>
      <link>https://lente.dev/posts/favoritismo/</link>
      <pubDate>Sun, 19 Mar 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/favoritismo/</guid>
      <description>Quão frequentemente os senadores votam de acordo com Trump em função da margem de Trump em seus estados.</description>
      <content:encoded><![CDATA[<h2 id="uma-imagem-vale-mais-que-mil-palavras">Uma imagem vale mais que mil palavras</h2>
<p>Este é um gráfico mostrando quão frequentemente os senadores votam de acordo com Trump em função da margem de Trump em seus estados.
A cor de cada ponto também indica o partido de cada senador (azuis são Democratas e vermelhos são Republicanos).</p>
<figure><img src="https://lente.dev/posts/favoritism/plot.webp"/>
</figure>
<p>Dados coletados e mantidos por FiveThirtyEight em <a href="https://projects.fivethirtyeight.com/congress-trump-score/">Tracking Congress In The Age Of Trump</a>.
Extraído com um <a href="https://github.com/clente/fivr">pacote R</a> que criei.</p>
<p>Você também pode ver a base completa no <a href="https://www.kaggle.com/clente/trump-score">Kaggle</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Férias pagas</title>
      <link>https://lente.dev/posts/ferias-pagas/</link>
      <pubDate>Sat, 11 Feb 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/ferias-pagas/</guid>
      <description>Uma análise da Cota para o Exercício da Atividade Parlamentar (CEAP) dos deputados federais do Brasil.</description>
      <content:encoded><![CDATA[<p>Caso você não saiba (assim como eu mesmo não sabia até alguns dias atrás),
os nossos deputados federais têm direito a uma Cota para o Exercício
da Atividade Parlamentar (CEAP), ou seja &ldquo;[uma quantia] destinada a
custear os gastos dos deputados exclusivamente vinculados ao exercício
da atividade parlamentar&rdquo;.</p>
<p>Cada deputado tem direito a R$42.000,00 reembolsáveis todo mês, variando
um pouco de estado para estado.</p>
<p>Já que os dados sobre todos os reembolsos requisitados estão disponíveis
no <a href="http://www2.camara.leg.br/transparencia/cota-para-exercicio-da-atividade-parlamentar/dados-abertos-cota-parlamentar">portal da transparência</a> da Câmara, eu decidi fazer uma pequena análise
para descobrir se os deputados usaram a CEAP adequadamente em 2016. Ao meu ver
há duas formas de identificar reembolsos irregulares dada a informação
disponível:</p>
<ul>
<li>Se a categoria do reembolso for suspeita</li>
<li>Se o componente temporal do reembolso for suspeito</li>
</ul>
<p>Comecemos pelo primeiro caminho.</p>
<h2 id="categoria-suspeita-divulgação-da-atividade-parlamentar">Categoria Suspeita: Divulgação da Atividade Parlamentar</h2>
<p>Quando os deputados requisitam um reembolso, eles precisam inserí-lo em
uma das 17 categorias possíveis, dentre as quais temos &ldquo;telefonia&rdquo;,
&ldquo;combustíveis e lubrificantes&rdquo;, &ldquo;emissão de bilhete aéreo&rdquo;, etc.
Para ter uma ideia de com o que eu estava lidando, somei o valor de todos
os reembolsos atrelados a cada categoria e criei um gráfico com as top 7.</p>
<figure><img src="https://lente.dev/posts/paid-vacations/bar.webp"/>
</figure>
<p>A categoria que custou mais para o bolso do brasileiro foi uma certa
surpresa para mim: divulgação da atividade parlamentar. Essa categoria
representou mais ou menos 23% (R$48.645.429,54) de um total de 212
milhões de reais reembolsados no ano passado.</p>
<p>Vendo esses números e o título estranhamente vago da categoria, fiquei
com a impressão de que ela estaria sendo utilizada por deputados para
cobrir gastos pessoais. De modo a ter certeza de que eu não estava sendo
rápido demais em meu julgamento, criei box-plots das 7 categorias com
maiores reembolsos medianos para que eu pudesse analisar seus outliers.</p>
<figure><img src="https://lente.dev/posts/paid-vacations/box.webp"/>
</figure>
<p>Na imagem acima podemos ver que divulgação de atividade parlamentar
(terceiro box da esquerda para a direita) não tem a maior mediana, mas
seus outliers se destacam muito do resto. Se examinarmos o ponto mais
alto da figura toda, vemos que ele representa um deputado reembolsando
um total de R$184.500,00 gastos em <em>uma pequena gráfica</em>.</p>
<p>Esses outliers (muitos dos quais estouram o teto de reembolso mensal
de qualquer estado) corroboram para a teoria de que a divulgação de
atividade parlamentar está sendo usada para enriquecimento pessoal por
parte de nossos deputados.</p>
<h2 id="componente-temporal-suspeito-férias-pagas">Componente Temporal Suspeito: Férias Pagas</h2>
<p>Partindo para a análise do componente temporal, tirei
a média do valor dos reembolsos de cada dia do ano; com isso pode-se
descobrir se existe algum período em que os reembolsos ficam
mais caros.</p>
<p>Depois de criar inúmeras visualizações com essas médias (que você pode
reproduzir com o código disponível no
<a href="https://github.com/clente/Kaggle/tree/master/House">meu repositório</a>),
achei algo estranho no gráfico abaixo. Ele representa a <a href="https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_densidade">distribuição de densidade</a> do
valor médio dos reembolsos de cada dia. Veja se você consegue identificar
o que chamou minha atenção&hellip;</p>
<figure><img src="https://lente.dev/posts/paid-vacations/density.webp"/>
</figure>
<p>Observe as pequenas &ldquo;lombadas&rdquo; depois da marca dos 1,5 mil reais. Elas
indicam que há um número grande, porém irregular, de dias em que a média
do valor dos reembolsos estoura. Se encontrarmos um padrão temporal na
distribuição desses outliers, isso pode significar que existe algo
suspeito acontecendo.</p>
<p>Para estudar essa hipótese, gerei a série temporal do valor do reembolso
médio dia a dia. As subidas e descidas ao longo do ano são as tendências
semanais, mas preste atenção ao que acontece no lado direito do gráfico.</p>
<figure><img src="https://lente.dev/posts/paid-vacations/ts.webp"/>
</figure>
<p>O pico em torno do final de dezembro e o início de janeiro representa
que nesses dias os reembolsos tiveram em média valores muito altos. Se
juntarmos isso com uma informação extra do portal da Câmara, vemos que
esse aumento repentino do valor se concentra no período após o dia 23 de
dezembro (linha laranja vertical), em que os deputados saem de férias.</p>
<p>Na minha opinião essa série temporal mostra que alguns deputados podem
estar utilizando A CEAP para pagar por suas férias.</p>
<h2 id="conclusão">Conclusão</h2>
<p>Esta não foi de maneira alguma uma análise exaustiva, mas mostra
indícios de que nossos deputados estão usando dinheiro público
para cobrir despesas pessoais. No começo nos propusemos
a investigar apenas dois aspectos da base de dados e já fomos capazes
de encontrar atividade suspeita em ambos; provavelmente ainda há muitas
outras formas de olhar para esses dados para as quais não tive tempo
ou habilidade, então lhes encorajo a que tentem explorar as &ldquo;maravilhas&rdquo;
da CEAP por conta própria.</p>
<p>Se você quiser ver a versão a interativa da análise deste artigo ou baixar
os dados que utilizei, visite meu Kaggle Kernel
<a href="https://www.kaggle.com/clente/d/epattaro/brazils-house-of-deputies-reimbursements/paid-vacations-brazil-s-house-of-deputies">Paid Vacations - Brazil’s House of Deputies</a>.
E se você quiser ver outros estudos sobre a CEAP, eu sugiro que você entre
no site da <a href="https://serenatadeamor.org/">Operação Serenata de Amor</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Globo interativo em R</title>
      <link>https://lente.dev/posts/globo-interativo/</link>
      <pubDate>Wed, 08 Feb 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/globo-interativo/</guid>
      <description>Como criar um globo 3D interativo no R usando o pacote threejs e as estatísticas comerciais do Japão.</description>
      <content:encoded><![CDATA[<p>Eu sou viciado em visualizações geográficas; eu acho que ela realmente colocam os dados em perspectiva, como se cada ponto tivesse seu lugar. Neste tutorial vou te ensinar a criar um globo 3D interativo bastante interessante com o pacote <code>threejs</code>.</p>
<h2 id="introdução">Introdução</h2>
<p>Nosso objetivo é visualizar o comércio do Japão com arcos em uma animação tridimensional da Terra. A base de dados que utilizaremos (<a href="https://www.kaggle.com/zanjibar/japan-trade-statistics/kernels">Japan Trade Statistics</a>, por <a href="https://www.kaggle.com/zanjibar">Tadashi Nagao</a>) é um ótimo exemplo do que encontramos no dia-a-dia: os dados têm informação apenas sobre os países (seus nomes registrados de forma desordenada) e têm não tem absolutamente nenhum dado sobre suas coordenadas.</p>
<p>Criaremos a visualização em 3 passos: pegar as coordenadas da capital de cada país, converter os nomes dos países para um formado padrão e criar o globo em si.</p>
<h2 id="pegando-as-coordenadas">Pegando as coordenadas</h2>
<p>Nossa primeira tarefa é importar os dados.</p>
<p>Eu carreguei os dados com informação do comércio japonês, carreguei a tabela com a relação país/código e então juntei as duas em um <em>data frame</em>. Eu também converti os nomes das colunas para caixa baixa e agrupei a tabela por país (somando os valores de todo o comércio com cada país). Nada disso é mostrado aqui por ser muito pouco geral, mas este foi o resultado:</p>
<table>
<thead>
<tr>
<th>country_name</th>
<th>country</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Afghanistan</td>
<td>130</td>
<td>8764947</td>
</tr>
<tr>
<td>Albania</td>
<td>229</td>
<td>1473130</td>
</tr>
<tr>
<td>Algeria</td>
<td>503</td>
<td>59532804</td>
</tr>
<tr>
<td>American_Oceania</td>
<td>622</td>
<td>4914</td>
</tr>
<tr>
<td>American_Samoa</td>
<td>621</td>
<td>276510</td>
</tr>
<tr>
<td>Andorra</td>
<td>212</td>
<td>29382</td>
</tr>
</tbody>
</table>
<p>Depois desse setup inicial, podemos seguir em frente e pegar as coordenadas da capital de cada país com o pacote <code>maps</code> (vamos usar as coordenadas das capitais como os &ldquo;pontos de aterrissagem&rdquo; dos arcos no globo 3D). Aqui vou carregar a tabela <code>world.cities</code> e selecionar os nomes dos países, suas capitais e suas coordenadas.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar as coordenadas de cada capital</span>
</span></span><span class="line"><span class="cl"><span class="n">capitals</span> <span class="o">&lt;-</span> <span class="n">world.cities</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">filter</span><span class="p">(</span><span class="n">capital</span> <span class="o">==</span> <span class="m">1</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">transmute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">country_name</span> <span class="o">=</span> <span class="n">country.etc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">lat</span> <span class="o">=</span> <span class="n">lat</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">long</span> <span class="o">=</span> <span class="n">long</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">rbind</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s">&#34;Hong Kong&#34;</span><span class="p">,</span> <span class="m">22.39</span><span class="p">,</span> <span class="m">114.1</span><span class="p">))</span></span></span></code></pre></div><p>Obs.: Não nos deixemos levar pela geopolítica, mas eu adicionei Hong Kong manualmente porque aparentemente ela é/não é parte da China, então ela não está na tabela <code>world.cities</code>…</p>
<p>Essa é a cara da tabela <code>capitals</code>:</p>
<table>
<thead>
<tr>
<th>country_name</th>
<th>lat</th>
<th>long</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jordan</td>
<td>31.95</td>
<td>35.93</td>
</tr>
<tr>
<td>United Arab Emirates</td>
<td>24.48</td>
<td>54.37</td>
</tr>
<tr>
<td>Nigeria</td>
<td>9.18</td>
<td>7.17</td>
</tr>
<tr>
<td>Ghana</td>
<td>5.56</td>
<td>-0.2</td>
</tr>
<tr>
<td>Pitcairn</td>
<td>-25.05</td>
<td>-130.1</td>
</tr>
<tr>
<td>Ethiopia</td>
<td>9.03</td>
<td>38.74</td>
</tr>
</tbody>
</table>
<h2 id="convertendo-os-nomes-dos-países">Convertendo os nomes dos países</h2>
<p>Preste atenção em como &ldquo;American Samoa&rdquo; e &ldquo;United Arab Emirates&rdquo; estão escritos nas duas tabelas acima (esse é o principal motivo pelo qual eu as incluí). Eles não estão formatados da mesma maneira.</p>
<p>Eu vou te poupar dos detalhes, mas esta é a parte mais difícil de trabalhar com dados geográficos: os nomes são um saco. As duas tabelas com as quais temos que trabalhar têm os nomes formatados de maneiras muito diferentes, então temos que padronizá-los.</p>
<p>Vamos fazer isso com o pacote <code>countrycodes</code>, mais especificamente com a base <code>countrycode_data</code>. Ela têm uma coluna com comandos regex que conseguem encontrar o nome de cada país quase independentemente da forma que ele estiver escrito. Primeiramente eu faço uma pequena limpeza em <code>trades\$country_name</code>, mas depois é simples assim:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar o regex de cada país</span>
</span></span><span class="line"><span class="cl"><span class="n">regex</span> <span class="o">&lt;-</span> <span class="n">countrycode</span><span class="o">::</span><span class="n">countrycode_data</span><span class="o">$</span><span class="n">country.name.en.regex</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Pegar a correspondência entre os países de &#39;totals&#39; e</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#39;capitals&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">trades_capitals</span> <span class="o">&lt;-</span> <span class="nf">as_tibble</span><span class="p">(</span><span class="nf">cbind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">regex</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">trades_countries</span> <span class="o">=</span> <span class="nf">match_country</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">trades</span><span class="o">$</span><span class="n">country_name</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="n">capitals_countries</span> <span class="o">=</span> <span class="nf">match_country</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">capitals</span><span class="o">$</span><span class="n">country_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">))</span></span></span></code></pre></div><p>No código acima estou omitindo a função <code>match_country</code>, que simplesmente associa cada entrada em <code>regex</code> com uma entrada do segundo argumento, mas o código em si é bem simples! E agora temos a tabela que conecta os nomes em <code>trades</code> com os nomes em <code>capitals</code>, que pode ser usada para juntas as duas em uma nova tabela chamada <code>geo_trades</code>.</p>
<h2 id="criando-o-globo">Criando o globo</h2>
<p>Para criar os arcos no globo precisamos de uma tabela com um formato bastante especial. Ela precisa conter 4 colunas: <code>origin_lat</code>, <code>origin_long</code>, <code>dest_lat</code>, e <code>dest_long</code> que serão os pontos iniciais e finais para cada arco no globo.</p>
<p>Eu vou usar <code>geo_trades</code> para criar uma nova tabela chamada <code>arcs</code> (nossa tabela também terá o valor da comércio entre as duas pontas, mas vamos excluir essa coluna quando passarmos a tabela para a função que gerará o globo). É assim que eu criei <code>arcs</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Criar origem e destino dos arcos (origem é sempre Tóquio)</span>
</span></span><span class="line"><span class="cl"><span class="n">arcs</span> <span class="o">&lt;-</span> <span class="n">geo_trades</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">cbind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">origin_lat</span> <span class="o">=</span> <span class="m">35.68</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">origin_long</span> <span class="o">=</span> <span class="m">139.69</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">country_name</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">  <span class="nf">transmute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">origin_lat</span> <span class="o">=</span> <span class="n">origin_lat</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">origin_long</span> <span class="o">=</span> <span class="n">origin_long</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">dest_lat</span> <span class="o">=</span> <span class="n">lat</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">dest_long</span> <span class="o">=</span> <span class="n">long</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span></span></span></code></pre></div><p>E agora o grand finale: essa é a função que usamos para gerar o globo 😁 Se você olhar com cuidado para a imagem abaixo, é possível ver que a grossura de cada linha representa o volume monetário total das trocas comerciais entre o Japão e cada país.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Pegar a imagem do globo</span>
</span></span><span class="line"><span class="cl"><span class="n">earth</span> <span class="o">&lt;-</span> <span class="nf">system.file</span><span class="p">(</span><span class="s">&#34;images/world.jpg&#34;</span><span class="p">,</span>  <span class="n">package</span> <span class="o">=</span> <span class="s">&#34;threejs&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Criar globo</span>
</span></span><span class="line"><span class="cl"><span class="nf">globejs</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">img</span> <span class="o">=</span> <span class="n">earth</span><span class="p">,</span> <span class="n">lat</span> <span class="o">=</span> <span class="n">arcs</span><span class="o">$</span><span class="n">dest_lat</span><span class="p">,</span> <span class="n">long</span> <span class="o">=</span> <span class="n">arcs</span><span class="o">$</span><span class="n">dest_long</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">arcs</span> <span class="o">=</span> <span class="n">arcs[</span><span class="p">,</span> <span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="n">]</span><span class="p">,</span> <span class="n">arcsOpacity</span> <span class="o">=</span> <span class="m">0.6</span><span class="p">,</span> <span class="n">arcsHeight</span> <span class="o">=</span> <span class="m">0.8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">arcsLwd</span> <span class="o">=</span> <span class="n">arcs</span><span class="o">$</span><span class="n">value</span><span class="p">,</span> <span class="n">arcsColor</span> <span class="o">=</span> <span class="s">&#34;green&#34;</span><span class="p">,</span> <span class="n">atmosphere</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">height</span> <span class="o">=</span> <span class="m">800</span><span class="p">,</span> <span class="n">width</span> <span class="o">=</span> <span class="m">800</span><span class="p">,</span> <span class="n">bg</span> <span class="o">=</span> <span class="s">&#34;white&#34;</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="m">4</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div><figure><img src="https://lente.dev/posts/interactive-globe/globe.webp"/>
</figure>
<p>E se você quiser interagir com o globo, por favor vá para o meu <a href="https://www.kaggle.com/clente/d/zanjibar/japan-trade-statistics/3d-interactive-globe-tutorial">Kaggle kernel</a> onde o HTML funciona melhor.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Espaço e tempo em R</title>
      <link>https://lente.dev/posts/animacao-mapa/</link>
      <pubDate>Tue, 17 Jan 2017 00:00:00 +0000</pubDate><author>c@lente.dev (Caio Lente)</author>
      <guid>https://lente.dev/posts/animacao-mapa/</guid>
      <description>Como criar um GIF para exibir dados espaciais e temporais no R usando os pacotes ggplot2 e animation.</description>
      <content:encoded><![CDATA[<p>Enquanto criava um <a href="https://www.kaggle.com/kernels">Kaggle Kernel</a> para a base de dados <a href="https://www.kaggle.com/the-guardian/the-counted">Killed by Police, 2015–2016</a>, eu tive a ideia de visualizar os dados com uma animação. Já que as tabelas tinham informações sobre toda morte causada por policiais entre 2015 e 2016 com as coordenadas de cada morte, pensei que cada <em>frame</em> poderia ser um gráfico que representasse todas as mortes até um dia em particular. Parecia bastante simples, mas no final demorou mais do que eu imaginava.</p>
<h2 id="criando-o-gráfico-estático">Criando o gráfico estático</h2>
<p>O primeiro passo era criar um gráfico estático para que eu pudesse ter uma ideia de como eu queria que a imagem final ficasse. Eu nunca tinha feito nenhum gráfico em R com dados geográficos, então demorei um pouco antes de ter certeza de que tudo estava funcionando. Eu decidi criar uma camada base para o gráfico e só então me preocupar com os dados.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">plot_deaths</span> <span class="o">&lt;-</span> <span class="nf">ggplot</span><span class="p">()</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">geom_polygon</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="nf">map_data</span><span class="p">(</span><span class="s">&#34;usa&#34;</span><span class="p">),</span> <span class="nf">aes</span><span class="p">(</span><span class="n">long</span><span class="p">,</span> <span class="n">lat</span><span class="p">,</span> <span class="n">group</span> <span class="o">=</span> <span class="n">group</span><span class="p">),</span> <span class="n">fill</span> <span class="o">=</span> <span class="s">&#34;#e6e6e6&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">theme</span><span class="p">(</span><span class="n">axis.text.x</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span> <span class="n">axis.text.y</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="n">axis.title.x</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span> <span class="n">axis.title.y</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="n">axis.line</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span> <span class="n">axis.ticks</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="n">panel.background</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span> <span class="n">panel.border</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="n">panel.grid.major</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span> <span class="n">panel.grid.minor</span> <span class="o">=</span> <span class="nf">element_blank</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="n">legend.position</span> <span class="o">=</span> <span class="s">&#34;none&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">coord_quickmap</span><span class="p">()</span></span></span></code></pre></div><p>O código acima cria essa imagem:</p>
<figure><img src="https://lente.dev/posts/map-animation/simple.webp"/>
</figure>
<p>Então filtrei a base para que ela contivesse apenas informação sobre os Estados Unidos continentais, que eu chamei de <code>cont_deaths</code>. Depois de uma limpeza, eu também criai a lista de cidades (e suas respectivas localizações) que tinha mais de 5 mortes registradas na base: <code>deadly_cities</code>.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">plot_deaths</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">geom_text_repel</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">deadly_cities</span><span class="p">,</span> <span class="nf">aes</span><span class="p">(</span><span class="n">long</span><span class="p">,</span> <span class="n">lat</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="n">city</span><span class="p">),</span> <span class="n">size</span> <span class="o">=</span> <span class="m">4</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">geom_point</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">cont_deaths</span><span class="p">,</span> <span class="nf">aes</span><span class="p">(</span><span class="n">longitude</span><span class="p">,</span> <span class="n">latitude</span><span class="p">),</span> <span class="n">alpha</span> <span class="o">=</span> <span class="m">0.2</span><span class="p">,</span> <span class="n">color</span> <span class="o">=</span> <span class="s">&#34;red&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">ggtitle</span><span class="p">(</span><span class="s">&#34;Killed by Police (showing cities with most deaths)&#34;</span><span class="p">)</span></span></span></code></pre></div><p>Eu tentei usar a função <code>geom_text</code> do pacote <code>ggplot</code> mas muitas cidades se sobrepunham, então procurei uma solução e acamei descobrindo o pacote <code>ggrepel</code>. Com <code>ggrepel::geom_text_repel</code>, o gráfico acabou ficando bem legal.</p>
<p>Na imagem abaixo, as cidades nomeadas são as com 5 ou mais mortes.</p>
<figure><img src="https://lente.dev/posts/map-animation/killings.webp"/>
</figure>
<p>Eu estava satisfeito com os resultados, então decidi começar a trabalhar na animação.</p>
<h2 id="criando-a-animação">Criando a animação</h2>
<p>Para criar a animação, usei o pacote <code>animation</code> e instalei um programa chamado ImageMagick. Com <code>animation::saveGIF</code> tudo que tive que fazer foi um loop em que gerava o gráfico de fada <em>frame</em> e o pacote cuidava do resto.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">saveGIF</span><span class="p">(</span><span class="kr">for</span> <span class="p">(</span><span class="n">i</span> <span class="kr">in</span> <span class="m">0</span><span class="o">:</span><span class="m">730</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Filter deaths up to a certain date</span>
</span></span><span class="line"><span class="cl">  <span class="n">time_deaths</span> <span class="o">&lt;-</span> <span class="n">cont_deaths</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">filter</span><span class="p">(</span><span class="n">date</span> <span class="o">&lt;=</span> <span class="nf">ymd</span><span class="p">(</span><span class="s">&#34;2015-01-01&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Get the cities that have already had more than 5 deaths</span>
</span></span><span class="line"><span class="cl">  <span class="n">time_cities</span> <span class="o">&lt;-</span> <span class="n">deadly_cities</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">left_join</span><span class="p">(</span><span class="n">time_deaths</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;city&#34;</span> <span class="o">=</span> <span class="s">&#34;city&#34;</span><span class="p">,</span> <span class="s">&#34;country.etc&#34;</span> <span class="o">=</span> <span class="s">&#34;state&#34;</span><span class="p">))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">group_by</span><span class="p">(</span><span class="n">city</span><span class="p">,</span> <span class="n">country.etc</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">summarise</span><span class="p">(</span><span class="n">count</span> <span class="o">=</span> <span class="nf">n</span><span class="p">(),</span> <span class="n">long</span> <span class="o">=</span> <span class="n">long[1]</span><span class="p">,</span> <span class="n">lat</span> <span class="o">=</span> <span class="n">lat[1]</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ungroup</span><span class="p">()</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">    <span class="nf">mutate</span><span class="p">(</span><span class="n">alph</span> <span class="o">=</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="m">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Plot deaths</span>
</span></span><span class="line"><span class="cl">  <span class="nf">print</span><span class="p">(</span><span class="n">plot_deaths</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">geom_text_repel</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">time_cities</span><span class="p">,</span> <span class="n">size</span> <span class="o">=</span> <span class="m">4</span><span class="p">,</span> <span class="n">segment.alpha</span> <span class="o">=</span> <span class="m">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nf">aes</span><span class="p">(</span><span class="n">long</span><span class="p">,</span> <span class="n">lat</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="n">city</span><span class="p">,</span> <span class="n">alpha</span> <span class="o">=</span> <span class="nf">factor</span><span class="p">(</span><span class="n">alph</span><span class="p">)))</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">scale_alpha_manual</span><span class="p">(</span><span class="n">values</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">1</span><span class="p">))</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">geom_point</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">time_deaths</span><span class="p">,</span> <span class="nf">aes</span><span class="p">(</span><span class="n">longitude</span><span class="p">,</span> <span class="n">latitude</span><span class="p">),</span> <span class="n">alpha</span> <span class="o">=</span> <span class="m">0.2</span><span class="p">,</span> <span class="n">color</span> <span class="o">=</span> <span class="s">&#34;red&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ggtitle</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;Deaths until &#34;</span><span class="p">,</span> <span class="nf">ymd</span><span class="p">(</span><span class="s">&#34;2015-01-01&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="s">&#34; (showing when each city crosses the 5 deaths line)&#34;</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="s">&#34;deaths.gif&#34;</span><span class="p">,</span> <span class="n">interval</span> <span class="o">=</span> <span class="m">0.005</span><span class="p">,</span> <span class="n">ani.width</span> <span class="o">=</span> <span class="m">900</span><span class="p">,</span> <span class="n">ani.height</span> <span class="o">=</span> <span class="m">630</span><span class="p">)</span></span></span></code></pre></div><p>Neste código fiz um loop nos 730 dias da base e gerei gráficos somente com as mortes até cada data. Também verifiquei para ver se nenhuma cidade tinha cruzado a linha das 5 mortes para começar a mostrar o seu nome.</p>
<p>Esta é a animação final:</p>
<figure><img src="https://lente.dev/posts/map-animation/animation.gif"/>
</figure>
<h2 id="palavras-finais">Palavras finais</h2>
<p>Tentar criar essa animação foi uma experiência muito interessante. Eu tive que procurar quase tudo que tentava fazer, mas no final aprendi bastante. Créditos especiais para Rob Harrand, pessoa cujo <a href="https://www.kaggle.com/tentotheminus9/d/cdc/zika-virus-epidemic/the-spread-of-the-zika-virus/code">Kernel</a> me ensinou a usar o pacote <code>animation</code>.</p>
<p>A pior parte foi fazer os rótulos das cidades se comportarem. Dado que <code>ggrepel::geom_text_repel</code> acha o melhor lugar para cada rótulo, conforme novas cidades cruzavam a linha das 5 mortes, os outros rótulos pulavam de um lado para o outro por alguns <em>frames</em>. Eu consertei isso fazendo com que todos os rótulos fossem mostrados desde o primeiro <em>frame</em> e deixando os rótulos das cidades que ainda não deveriam aparecer com o texto transparente.</p>
<p>Se você quiser dar uma olhada no código fonte completo, dê uma olhada no meu <a href="https://www.kaggle.com/clente/d/the-guardian/the-counted/the-counted-geographic-and-temporal-overview">Kernel</a>.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
