Quod erat demonstrandum
Programação de Eventos 101
Pré-requisitos:
1 Introdução
Essa aula tem como objetivo ensinar programação por eventos no RPG Maker. A intenção é ser uma aula introdutória, então não usaremos Script Calls, que são comandos avançados.
Para isso, vamos usar a versão mais apropriada do RPG Maker para esse objetivo: o RPG Maker VX Ace. Note que esse tutorial não funciona com as versões menos avançadas da engine, como o RPG Maker 2000, RPG Maker 2k3, RPG Maker MV ou RPG Maker MZ. As versões VX e XP servem, mas são ultrapassadas então desconsideramos ambas neste tutorial.
2 Anatomia de um Evento
O editor de eventos do RPG Maker é bastante simples, sendo composto por apenas 9 seções, contendo 13 dropdowns, 10 checkboxes e 9 botões, além de uma área de entrada de texto, uma lista interativa para os comandos e uma área de seleção de gráfico.
Para fins deste tutorial, vamos nos concentrar nas regiões destacadas na imagem:
2.1 Seleção de gráfico
Esta seção permite escolher o gráfico do evento. É bem maneiro.
2.2 Ativador
O ativador determina quando os comandos do evento são executados.
Existem cinco tipos de ativador:
2.3 Conteúdo
Esta seção é onde inserimos os comandos de fato. Ao clicar duas vezes em uma linha da lista, vemos a seguinte janela:
E quando inserimos um comando ele fica visível na janela, desta forma:
Note que a forma como ele exibe o comando não é nem um pouco críptica e/ou remanescente de linhas de comando primitivas, além de ser muito mais legível que código equivalente (como, por exemplo, message 'Hello World!'). Isso torna programar com eventos mais fácil que programar com scripts.
2.4 Condições
Por último mas não menos importante, temos a seção de condições do evento. As condições determinam condições de ativação adicionais para a execução do evento, como switches e valores de variáveis.
3 Variáveis
Variáveis são a parte mais fundamental da programação por eventos. Por isso, é importante entender elas profundamente antes de começarmos.
Algumas pessoas vão te dizer que as variáveis nos eventos são a mesma coisa que as variáveis na matemática, mas isso além de não explicar muita coisa (quase ninguém entende direito as variáveis na matemática), é um pouco enganoso.
Na matemática (em especial na lógica), comumente, existem dois tipos de variável: variáveis livres e variáveis ligadas (Ler mais). Uma variável livre funciona como uma lacuna a ser preenchida, e só faz sentido no contexto de uma função ou predicado (por exemplo, na função x^2 + x, x é variável livre). Uma variável ligada, por outro lado, sempre tem uma condição associada e pode aparecer em uma expressão isolada (por exemplo, em ∀x,p,q (∃m (p = mq) ∧ x|p -> x|m ∧ x|q), x, p, q e m são variáveis ligadas).
Mas o que isso tem a ver com eventos? Bom, não muito. Na prática, é muito difícil pensar em eventos como funções ou objetos matemáticos similares, então a analogia das variáveis deixa a desejar.
Ao invés disso, podemos pensar em variáveis como "caixas", onde cada caixa pode conter um número. As caixas são independentes, e eu posso tirar e colocar o que quiser nelas; além disso, se quiser, posso combinar o conteúdo de duas caixas (e.g. somar uma em outra, subtrair, dividir, etc.)
3.1 Operações com variáveis
O RPG Maker permite algumas operações com as variáveis, visíveis na janela do comando "Controle de Variáveis" (primeira aba, segundo item na seção "Progressão do Jogo").
Neste tutorial, usaremos as seis operações disponíveis, mas nos limitaremos aos operandos "Constante" e "Variável", visto que os outros três (principalmente o Script) são muito avançados.
Todas as operações devem ser relativamente autoexplicativas, exceto talvez a de "Resto". O "Resto" executa a operação de resto da divisão na variável, permitindo que façamos cálculos usando Aritmética Modular. Isso será crucial para programarmos com eventos! /o/
Um exemplo comum de aritmética modular são os ponteiros de um relógio: no relógio, temos marcas de 1 a 12, e quando somamos valores maiores que 12 (ou menores que 1) o ponteiro "dá a volta". Por exemplo, no relógio, 5 + 10 ≡ 3, 12 + 1 ≡ 1, x + 12 ≡ x, etc.; dizemos então que 5 + 10 ≡ 3 (mod 12), 12 + 1 ≡ 1 (mod 12), e assim por diante. Em geral, n + x ≡ x (mod n).
4 Condições
Condições controlam o fluxo de execução do evento. Você pode por exemplo condicionar uma mensagem à ativação de uma switch:
E o evento ficaria assim:
Além disso, é possível definir condições sobre variáveis, usando alguns comparadores:
E assim como no comando de controle, podemos comparar com uma constante ou com outra variável:
Existem outras abas e outra condições para esse comando, mas eles são mais avançados, e por isso não os usaremos nesse tutorial.
5 Loops
Um loop executa repetidamente os comandos dentro de um bloco. No editor de eventos, o loop se parece com isso:
O nome "Loop" vem da palavra inglesa para "ciclo", que tem a ver com o fluxo de execução do evento quando o desenhamos:
Claro, um loop pode ser um problema se não sairmos dele (caso contrário todo o resto do evento abaixo do loop não seria executao!). Para isso, usamos o comando "Sair do loop", geralmente acompanhado de uma condição:
O exemplo acima conta até 10 com a variável "Exemplo" no loop, e então sai do Loop.
6 Bases numéricas
Uma base numérica (em inglês, radix) é uma instância de sistema numérico posicional. Se você já leu algo sobre computadores provavelmente deve ter pelo menos ouvido falar do tal "binário", que é usado internamente pelos computadores e ocasionalmente na computação.
O sistema binário é conveniente para o computador porque é fácil de construir eletronicamente, mas também tem suas vantagens além disso; em particular, cada dígito num número representado no sistema binário deve ser zero ou um, ou, equivalentemente, "verdadeiro" ou "falso".
Além do sistema binário, existem inúmeros sistemas numéricos (literalmente, existe pelo menos um para cada número real, e o conjunto dos reais é incontável), entre eles o decimal, que usamos normalmente, o hexadecimal que também é comum na programação, por ser relativamente fácil de traduzir para binário e ser mais compacto que o decimal, e o hexapentecontadiacosial (base 256), representado por uma string ASCII, com caracteres (dígitos) de 0 a 255.
6.1 S͉i͕s͈t͉ȩm̳a̪ Ḥe͈x̖a̻p̻ḙn̜t̙e̻c̱o͉n̼t͢a̪d̻i̫a̝c᷊ǫs͖i̼a̮l̗
Ok, o nome não existe, mas a construção é a mesma usada em "hexadecimal", então a partir de agora está valendo.
Este sistema numérico representa uma sequência de números de 0 a 255, e é útil em programação porque cada dígito do número representa um byte, equivalente a 8 bits (não coincidentemente, 2⁸ = 256), que é uma unidade de organização de bits extremamente comum em computadores.
Nos eventos do RPG Maker temos acesso apenas ao sistema numérico decimal, mas podemos converter entre as bases de forma relativamente simples. O artigo da Wikipedia sobre conversões de bases numéricas tem uma explicação detalhada sobre conversões entre bases quaisquer.
A ideia geral é que o n-ésimo dígito de um número em base x representa o número de vezes que o valor xⁿ deve ser adicionado ao valor final; por exemplo, na base decimal: o número 1234 tem o primeiro dígito (0-ésimo) igual a 4, o segundo ("1-ésimo") igual a 3, e assim por diante, logo o valor do número é 4×10⁰ + 3×10¹ + 2×10² + 1×10³ = 4 + 30 + 200 + 1000 = 1234 (claro).
Seguindo a mesma lógica, o número "1234" em base 256 seria equivalente a 4×256⁰ + 3×256¹ + 2×256² + 1×256³ = (1690906)₁₀.
Mas para representar números na base 256 não bastam os 10 dígitos usuais (0-9), nem mesmo os 16 extendidos usados no hexadecimal (0-9, a-f). Para dar conta de todas as possibilidades, representaremos um único dígito na base 256 usando pares de dígitos hexadecimais, separando cada dígito com espaços por clareza. Por exemplo, o número 238×256⁰ + 255×256¹ + 192×256² seria representado como (C0 FF EE)₂₅₆. Ao mesmo tempo, podemos converter esse valor em decimal (e vice versa), calculando seu valor como usual: 238×256⁰ + 255×256¹ + 192×256² = 238 + 255×256 + 192×65536 = (12648430)₁₀.
Podemos usar a Calculadora de Programador do Windows™ para calcular esses valores, e convenientemente fazer as conversões para binário e hexadecimal:
Com esse exemplo em mãos, podemos também analisar como fazemos para "extrair" um único dígito de um número numa base qualquer. De forma geral, o n-ésimo (contando do 0) dígito D de um número X na base B segue a seguinte igualdade: D ≡ ⌊X / Bⁿ⌋ (mod B), isto é, D é o resto da divisão de X / Bⁿ (arredondando para baixo) por B.
Na base 10, isso quer dizer por exemplo que o 2º dígito (1-ésimo) de 1234 é ⌊1234 / 10¹⌋ (mod 10) ≡ 123 (mod 10) ≡ 12×10 + 3 (mod 10) ≡ 3 (mod 10).
Equivalentemente, na base 256, isso quer dizer que o 1º dígito (0-ésimo) de (C0 FF EE)₂₅₆ é ⌊(C0 FF EE)₂₅₆ / 1⌋ (mod 256) ≡ (C0 FF EE)₂₅₆ (mod 256) ≡ (EE)₂₅₆ (mod 256).
De forma resumida, dividir um número pela base arredondando para baixo "descarta" o 0-ésimo dígito e tirar o resto descarta todos, exceto o 0-ésimo. Aplicando essas operações em sucessão (o expoente na base representa divisão repetida), conseguimos isolar um dígito arbitrário em um número naquela base.
Com isso, temos uma forma de obter e definir um dígito específico em um número representado em uma base numérica qualquer!
7 M̘̘͞͞e̫̫̿m̝̝︣︣ó̟̆̆r̠̠ͮͮi͈͈̔a̜̋̋ R̄͟͟Ǎ̙̙̌M̰̰᷀
O "RAM" na memória RAM do computador é uma sigla, do inglês Random Access Memory. O "Random" no nome quer dizer que a memória pode ser acessada em qualquer posição que se deseje. Isso é extremamente útil em computadores, porque permite que programas reservem áreas de memória e as acessem (para escrita e leitura) conforme precisarem.
Todo programa no computador usa memória RAM, e se vamos programar com eventos vamos precisar de algo equivalente.
Aí entra a nossa base recém-descoberta, a hexapentecontadiacosial. Na prática, a memória RAM do computador não passa de um único número (bem grande) na base 256. Cada byte na memória é um dígito, e um acesso na posição N na memória é equivalente a isolar o N-ésimo dígito desse numéro; escrever um byte na memória também é relativamente simples usando operações aritméticas:
Sendo assim, é bem possível simular a memória RAM usando uma única variável no RPG Maker! Aqui entra a superioridade da versão VX Ace da engine, visto que nela os eventos rodam em cima de Ruby, que tem suporte a Bignums por padrão. Em versões menos avançadas da engine, o número perderia suas propriedades a partir de certo valor. Por exemplo, no 2k ele provavelmente "daria a volta" e ficaria negativo, por motivos de Complemento para dois, e no MV ele provavelmente viraria um número de ponto flutuante, perdendo precisão e consequentemente informação. Sim, Ruby > All.
8 A̷̮ͣr̴̡͖̤᷊͓̈́q̷̡̏︡᷈͜ư̴̢̻̩͇ͮȋ̵͉̲́ͫ̎̕t̶͔̖̜ͮ᷇̾᷄͜͟e̴̢̝̱̓́t̷̟̩͉̳̜︢̋︠᷅u̵͚͗᷄ŗ̸͈͇͌̀ͪa̴͎̜̯͎︡͢ Ą̵̪̼̭̝͋ͥ͘R̶͖̭̩̤̤͆̈ͧ︣M̵̰̤͓͔̆v̴͓̦̝͉ͨ͌ͣͩ͒6̴̢̭᷿̎᷾︡̉͢-̴̭̰̜͔᷀́͆ͨ͢M̶᷊͔̩̠̏͜
Além de memória, todo computador tem um processador, que é o que de fato faz o trabalho de, você adivinhou, processar as coisas.
Mas o processamento não é mágica, e o processador precisa de uma forma de saber o que exatamente ele deve processar e como. Para isso, existem conjuntos de instruções, que fazem a interface entre os programas (software) e o hardware que os executa.
Para este tutorial introdutório, é interessante mantermos a complexidade ao mínimo. Para tanto, implementaremos uma arquitetura simples, com um conjunto de instruções reduzido.
Felizmente, existem as arquiteturas RISC, que são exatamente isso (a sigla significa Reduced Instruction Set Computer, ou "Computador com um conjunto reduzido de instruções"). Em especial, a arquitetura ARM (de Advanced RISC Machine) é muito bem documentada, e as especificações de diversas versões da arquitetura estão disponíveis gratuitamente no site da empresa.
Em particular, usaremos uma versão simplificada da já simples arquitetura Armv6-M, usada no processador Cortex M0 da ARM.
A implementação é relativamente simples, e usa apenas as técnicas descritas até agora. Para economizar tempo, você pode baixar a implementação pronta: Download do ZIP via Dropbox.
Essa implementação inclui apenas os eventos que simulam o processador, nenhum outro dado do projeto foi alterado.
8.1 C̸̪͚͍̿̒o̴͚̞̟̐͐m̸̡̻̝͐̐p̸̺̦͙̒͝ḯ̵͖̼͐͝l̴͕̠̟̔́͐a̴̞͕̔͘͝n̸̦͔͎̽̽d̵̫͉͍̾͘o̴̝̼̼̐́̚ p̵͔͖͕̿̈́̓a̵̝̠͎̾͒͝r̵̢̻͕͐̈́͋a̴̡͇͙̽̕͝ A̴̼͇̙͋͊͆R̴̝̠̙̐͌̈́M̸̼͎͚̚̕͝v̸̢̪͓̐͋̒6̴̫̞͔͑̔͝ c̸̦̘͉͌̀͝o̵̼̦͑̿͌m̴̡͎̀̈́̐͜ o̸̡͇͛̾͜͝ G̵̫͓̘͋͝͝C̸̝̙̘͌̈́̒C̵̡̘̦̾̒͝
Para que o processador faça algo, temos que escrever um programa com o que queremos, e então transformá-lo em um formato que o processador entenda.
Para isso, usaremos a linguagem C, e o toolchain de Arm do GCC. Deve ser possível fazer isso no Windows, mas é beem mais fácil no Linux; recomendo instalar o WSL com Ubuntu.
No Ubuntu, para instalar as ferramentas necessárias, basta executar os seguintes comandos:
Feito isso, os executáveis serão instalados com os nomes usuais (gcc, objdump, objcopy, etc.), mais o prefixo arm-none-eabi- (e.g. arm-none-eabi-gcc, arm-none-eabi-ld, ...).
Para as seções seguintes, usaremos o seguinte programa de teste, que lê uma lista de números via entrada do usuário e ordena usando insertion sort:
Nota: O algoritmo insertion sort foi escolhido por ser eficiente com coleções pequenas.
Pré-requisitos:
- RPG Maker VX Ace instalado
- Conhecimento básico de matemática (i.e. aritmética básica e aritmética modular/"do relógio")
- Nenhum conhecimento de scripts
1 Introdução
Essa aula tem como objetivo ensinar programação por eventos no RPG Maker. A intenção é ser uma aula introdutória, então não usaremos Script Calls, que são comandos avançados.
Para isso, vamos usar a versão mais apropriada do RPG Maker para esse objetivo: o RPG Maker VX Ace. Note que esse tutorial não funciona com as versões menos avançadas da engine, como o RPG Maker 2000, RPG Maker 2k3, RPG Maker MV ou RPG Maker MZ. As versões VX e XP servem, mas são ultrapassadas então desconsideramos ambas neste tutorial.
2 Anatomia de um Evento
O editor de eventos do RPG Maker é bastante simples, sendo composto por apenas 9 seções, contendo 13 dropdowns, 10 checkboxes e 9 botões, além de uma área de entrada de texto, uma lista interativa para os comandos e uma área de seleção de gráfico.
Para fins deste tutorial, vamos nos concentrar nas regiões destacadas na imagem:
2.1 Seleção de gráfico
Esta seção permite escolher o gráfico do evento. É bem maneiro.
2.2 Ativador
O ativador determina quando os comandos do evento são executados.
Existem cinco tipos de ativador:
- Botão de ação: Ativa o evento quando o jogador pressiona o botão de interação olhando para o evento
- Tocar Jogador: Ativa o evento quando ele toca o jogador
- Tocar Evento: Ativa o evento quando ele toca outro evento, não incluindo a si mesmo
- Executar Automático: Executa o evento em loop e trava o jogo. Não é útil, porque trava o jogo
- Processo Paralelo: Executa o evento em loop e não trava o jogo
2.3 Conteúdo
Esta seção é onde inserimos os comandos de fato. Ao clicar duas vezes em uma linha da lista, vemos a seguinte janela:
E quando inserimos um comando ele fica visível na janela, desta forma:
Note que a forma como ele exibe o comando não é nem um pouco críptica e/ou remanescente de linhas de comando primitivas, além de ser muito mais legível que código equivalente (como, por exemplo, message 'Hello World!'). Isso torna programar com eventos mais fácil que programar com scripts.
2.4 Condições
Por último mas não menos importante, temos a seção de condições do evento. As condições determinam condições de ativação adicionais para a execução do evento, como switches e valores de variáveis.
3 Variáveis
Variáveis são a parte mais fundamental da programação por eventos. Por isso, é importante entender elas profundamente antes de começarmos.
Algumas pessoas vão te dizer que as variáveis nos eventos são a mesma coisa que as variáveis na matemática, mas isso além de não explicar muita coisa (quase ninguém entende direito as variáveis na matemática), é um pouco enganoso.
Na matemática (em especial na lógica), comumente, existem dois tipos de variável: variáveis livres e variáveis ligadas (Ler mais). Uma variável livre funciona como uma lacuna a ser preenchida, e só faz sentido no contexto de uma função ou predicado (por exemplo, na função x^2 + x, x é variável livre). Uma variável ligada, por outro lado, sempre tem uma condição associada e pode aparecer em uma expressão isolada (por exemplo, em ∀x,p,q (∃m (p = mq) ∧ x|p -> x|m ∧ x|q), x, p, q e m são variáveis ligadas).
Mas o que isso tem a ver com eventos? Bom, não muito. Na prática, é muito difícil pensar em eventos como funções ou objetos matemáticos similares, então a analogia das variáveis deixa a desejar.
Ao invés disso, podemos pensar em variáveis como "caixas", onde cada caixa pode conter um número. As caixas são independentes, e eu posso tirar e colocar o que quiser nelas; além disso, se quiser, posso combinar o conteúdo de duas caixas (e.g. somar uma em outra, subtrair, dividir, etc.)
3.1 Operações com variáveis
O RPG Maker permite algumas operações com as variáveis, visíveis na janela do comando "Controle de Variáveis" (primeira aba, segundo item na seção "Progressão do Jogo").
Neste tutorial, usaremos as seis operações disponíveis, mas nos limitaremos aos operandos "Constante" e "Variável", visto que os outros três (principalmente o Script) são muito avançados.
Todas as operações devem ser relativamente autoexplicativas, exceto talvez a de "Resto". O "Resto" executa a operação de resto da divisão na variável, permitindo que façamos cálculos usando Aritmética Modular. Isso será crucial para programarmos com eventos! /o/
Um exemplo comum de aritmética modular são os ponteiros de um relógio: no relógio, temos marcas de 1 a 12, e quando somamos valores maiores que 12 (ou menores que 1) o ponteiro "dá a volta". Por exemplo, no relógio, 5 + 10 ≡ 3, 12 + 1 ≡ 1, x + 12 ≡ x, etc.; dizemos então que 5 + 10 ≡ 3 (mod 12), 12 + 1 ≡ 1 (mod 12), e assim por diante. Em geral, n + x ≡ x (mod n).
4 Condições
Condições controlam o fluxo de execução do evento. Você pode por exemplo condicionar uma mensagem à ativação de uma switch:
E o evento ficaria assim:
Além disso, é possível definir condições sobre variáveis, usando alguns comparadores:
E assim como no comando de controle, podemos comparar com uma constante ou com outra variável:
Existem outras abas e outra condições para esse comando, mas eles são mais avançados, e por isso não os usaremos nesse tutorial.
5 Loops
Um loop executa repetidamente os comandos dentro de um bloco. No editor de eventos, o loop se parece com isso:
O nome "Loop" vem da palavra inglesa para "ciclo", que tem a ver com o fluxo de execução do evento quando o desenhamos:
Claro, um loop pode ser um problema se não sairmos dele (caso contrário todo o resto do evento abaixo do loop não seria executao!). Para isso, usamos o comando "Sair do loop", geralmente acompanhado de uma condição:
O exemplo acima conta até 10 com a variável "Exemplo" no loop, e então sai do Loop.
6 Bases numéricas
Uma base numérica (em inglês, radix) é uma instância de sistema numérico posicional. Se você já leu algo sobre computadores provavelmente deve ter pelo menos ouvido falar do tal "binário", que é usado internamente pelos computadores e ocasionalmente na computação.
O sistema binário é conveniente para o computador porque é fácil de construir eletronicamente, mas também tem suas vantagens além disso; em particular, cada dígito num número representado no sistema binário deve ser zero ou um, ou, equivalentemente, "verdadeiro" ou "falso".
Além do sistema binário, existem inúmeros sistemas numéricos (literalmente, existe pelo menos um para cada número real, e o conjunto dos reais é incontável), entre eles o decimal, que usamos normalmente, o hexadecimal que também é comum na programação, por ser relativamente fácil de traduzir para binário e ser mais compacto que o decimal, e o hexapentecontadiacosial (base 256), representado por uma string ASCII, com caracteres (dígitos) de 0 a 255.
6.1 S͉i͕s͈t͉ȩm̳a̪ Ḥe͈x̖a̻p̻ḙn̜t̙e̻c̱o͉n̼t͢a̪d̻i̫a̝c᷊ǫs͖i̼a̮l̗
Ok, o nome não existe, mas a construção é a mesma usada em "hexadecimal", então a partir de agora está valendo.
Este sistema numérico representa uma sequência de números de 0 a 255, e é útil em programação porque cada dígito do número representa um byte, equivalente a 8 bits (não coincidentemente, 2⁸ = 256), que é uma unidade de organização de bits extremamente comum em computadores.
Nos eventos do RPG Maker temos acesso apenas ao sistema numérico decimal, mas podemos converter entre as bases de forma relativamente simples. O artigo da Wikipedia sobre conversões de bases numéricas tem uma explicação detalhada sobre conversões entre bases quaisquer.
A ideia geral é que o n-ésimo dígito de um número em base x representa o número de vezes que o valor xⁿ deve ser adicionado ao valor final; por exemplo, na base decimal: o número 1234 tem o primeiro dígito (0-ésimo) igual a 4, o segundo ("1-ésimo") igual a 3, e assim por diante, logo o valor do número é 4×10⁰ + 3×10¹ + 2×10² + 1×10³ = 4 + 30 + 200 + 1000 = 1234 (claro).
Seguindo a mesma lógica, o número "1234" em base 256 seria equivalente a 4×256⁰ + 3×256¹ + 2×256² + 1×256³ = (1690906)₁₀.
Mas para representar números na base 256 não bastam os 10 dígitos usuais (0-9), nem mesmo os 16 extendidos usados no hexadecimal (0-9, a-f). Para dar conta de todas as possibilidades, representaremos um único dígito na base 256 usando pares de dígitos hexadecimais, separando cada dígito com espaços por clareza. Por exemplo, o número 238×256⁰ + 255×256¹ + 192×256² seria representado como (C0 FF EE)₂₅₆. Ao mesmo tempo, podemos converter esse valor em decimal (e vice versa), calculando seu valor como usual: 238×256⁰ + 255×256¹ + 192×256² = 238 + 255×256 + 192×65536 = (12648430)₁₀.
Podemos usar a Calculadora de Programador do Windows™ para calcular esses valores, e convenientemente fazer as conversões para binário e hexadecimal:
Com esse exemplo em mãos, podemos também analisar como fazemos para "extrair" um único dígito de um número numa base qualquer. De forma geral, o n-ésimo (contando do 0) dígito D de um número X na base B segue a seguinte igualdade: D ≡ ⌊X / Bⁿ⌋ (mod B), isto é, D é o resto da divisão de X / Bⁿ (arredondando para baixo) por B.
Na base 10, isso quer dizer por exemplo que o 2º dígito (1-ésimo) de 1234 é ⌊1234 / 10¹⌋ (mod 10) ≡ 123 (mod 10) ≡ 12×10 + 3 (mod 10) ≡ 3 (mod 10).
Equivalentemente, na base 256, isso quer dizer que o 1º dígito (0-ésimo) de (C0 FF EE)₂₅₆ é ⌊(C0 FF EE)₂₅₆ / 1⌋ (mod 256) ≡ (C0 FF EE)₂₅₆ (mod 256) ≡ (EE)₂₅₆ (mod 256).
De forma resumida, dividir um número pela base arredondando para baixo "descarta" o 0-ésimo dígito e tirar o resto descarta todos, exceto o 0-ésimo. Aplicando essas operações em sucessão (o expoente na base representa divisão repetida), conseguimos isolar um dígito arbitrário em um número naquela base.
Com isso, temos uma forma de obter e definir um dígito específico em um número representado em uma base numérica qualquer!
7 M̘̘͞͞e̫̫̿m̝̝︣︣ó̟̆̆r̠̠ͮͮi͈͈̔a̜̋̋ R̄͟͟Ǎ̙̙̌M̰̰᷀
O "RAM" na memória RAM do computador é uma sigla, do inglês Random Access Memory. O "Random" no nome quer dizer que a memória pode ser acessada em qualquer posição que se deseje. Isso é extremamente útil em computadores, porque permite que programas reservem áreas de memória e as acessem (para escrita e leitura) conforme precisarem.
Todo programa no computador usa memória RAM, e se vamos programar com eventos vamos precisar de algo equivalente.
Aí entra a nossa base recém-descoberta, a hexapentecontadiacosial. Na prática, a memória RAM do computador não passa de um único número (bem grande) na base 256. Cada byte na memória é um dígito, e um acesso na posição N na memória é equivalente a isolar o N-ésimo dígito desse numéro; escrever um byte na memória também é relativamente simples usando operações aritméticas:
Código:
# RAM = número correspondente à RAM
# P = posição na memória
# V = valor para escrever (0-255)
escrita(RAM, P, V) = RAM - (⌊RAM / 256ᴾ⌋ (mod 256)) + V×256ᴾ
Sendo assim, é bem possível simular a memória RAM usando uma única variável no RPG Maker! Aqui entra a superioridade da versão VX Ace da engine, visto que nela os eventos rodam em cima de Ruby, que tem suporte a Bignums por padrão. Em versões menos avançadas da engine, o número perderia suas propriedades a partir de certo valor. Por exemplo, no 2k ele provavelmente "daria a volta" e ficaria negativo, por motivos de Complemento para dois, e no MV ele provavelmente viraria um número de ponto flutuante, perdendo precisão e consequentemente informação. Sim, Ruby > All.
8 A̷̮ͣr̴̡͖̤᷊͓̈́q̷̡̏︡᷈͜ư̴̢̻̩͇ͮȋ̵͉̲́ͫ̎̕t̶͔̖̜ͮ᷇̾᷄͜͟e̴̢̝̱̓́t̷̟̩͉̳̜︢̋︠᷅u̵͚͗᷄ŗ̸͈͇͌̀ͪa̴͎̜̯͎︡͢ Ą̵̪̼̭̝͋ͥ͘R̶͖̭̩̤̤͆̈ͧ︣M̵̰̤͓͔̆v̴͓̦̝͉ͨ͌ͣͩ͒6̴̢̭᷿̎᷾︡̉͢-̴̭̰̜͔᷀́͆ͨ͢M̶᷊͔̩̠̏͜
Além de memória, todo computador tem um processador, que é o que de fato faz o trabalho de, você adivinhou, processar as coisas.
Mas o processamento não é mágica, e o processador precisa de uma forma de saber o que exatamente ele deve processar e como. Para isso, existem conjuntos de instruções, que fazem a interface entre os programas (software) e o hardware que os executa.
Para este tutorial introdutório, é interessante mantermos a complexidade ao mínimo. Para tanto, implementaremos uma arquitetura simples, com um conjunto de instruções reduzido.
Felizmente, existem as arquiteturas RISC, que são exatamente isso (a sigla significa Reduced Instruction Set Computer, ou "Computador com um conjunto reduzido de instruções"). Em especial, a arquitetura ARM (de Advanced RISC Machine) é muito bem documentada, e as especificações de diversas versões da arquitetura estão disponíveis gratuitamente no site da empresa.
Em particular, usaremos uma versão simplificada da já simples arquitetura Armv6-M, usada no processador Cortex M0 da ARM.
A implementação é relativamente simples, e usa apenas as técnicas descritas até agora. Para economizar tempo, você pode baixar a implementação pronta: Download do ZIP via Dropbox.
Essa implementação inclui apenas os eventos que simulam o processador, nenhum outro dado do projeto foi alterado.
8.1 C̸̪͚͍̿̒o̴͚̞̟̐͐m̸̡̻̝͐̐p̸̺̦͙̒͝ḯ̵͖̼͐͝l̴͕̠̟̔́͐a̴̞͕̔͘͝n̸̦͔͎̽̽d̵̫͉͍̾͘o̴̝̼̼̐́̚ p̵͔͖͕̿̈́̓a̵̝̠͎̾͒͝r̵̢̻͕͐̈́͋a̴̡͇͙̽̕͝ A̴̼͇̙͋͊͆R̴̝̠̙̐͌̈́M̸̼͎͚̚̕͝v̸̢̪͓̐͋̒6̴̫̞͔͑̔͝ c̸̦̘͉͌̀͝o̵̼̦͑̿͌m̴̡͎̀̈́̐͜ o̸̡͇͛̾͜͝ G̵̫͓̘͋͝͝C̸̝̙̘͌̈́̒C̵̡̘̦̾̒͝
Para que o processador faça algo, temos que escrever um programa com o que queremos, e então transformá-lo em um formato que o processador entenda.
Para isso, usaremos a linguagem C, e o toolchain de Arm do GCC. Deve ser possível fazer isso no Windows, mas é beem mais fácil no Linux; recomendo instalar o WSL com Ubuntu.
No Ubuntu, para instalar as ferramentas necessárias, basta executar os seguintes comandos:
Bash:
sudo apt-get update -y
sudo apt-get install -y gcc-arm-none-eabi binutils-arm-none-eabi libc6-armel-cross libc6-dev-armel-cross
Feito isso, os executáveis serão instalados com os nomes usuais (gcc, objdump, objcopy, etc.), mais o prefixo arm-none-eabi- (e.g. arm-none-eabi-gcc, arm-none-eabi-ld, ...).
Para as seções seguintes, usaremos o seguinte programa de teste, que lê uma lista de números via entrada do usuário e ordena usando insertion sort:
C:
// arquivo: sample.c
#include <stdint.h>
#define RAM(offset) ((uint32_t*) (0x60000000 + (offset)))
#define STACK_BASE RAM(1024)
#define MEM(offset) (STACK_BASE + 4 * (1 + (offset)))
volatile uint32_t* peripheral = (uint32_t*) 0x40000000;
// Lê um word (32-bits) do dispositivo periférico mapeado (executa o comando
// de entrada numérica do evento e retorna o valor digitado)
inline static uint32_t input() {
return *peripheral;
}
// Escreve um word (32-bits) para o dispositivo periférico mapeado (mostra uma
// mensagem com o número)
inline static void output(uint32_t word) {
*peripheral = word;
}
uint32_t* elements = MEM(0);
// insertion sort
void sort(uint32_t* arr, uint32_t n) {
for (int i = 1; i < n; i++) {
uint32_t key = arr[i];
int j;
for (j = i - 1; j >= 0 && arr[j] > key; j--) {
arr[j + 1] = arr[j];
}
arr[j + 1] = key;
}
}
void _start() {
uint32_t n = input();
for (int i = 0; i < n; i++) {
elements[i] = input();
}
sort(elements, n);
for (int i = 0; i < n; i++) {
output(elements[i]);
}
}
Nota: O algoritmo insertion sort foi escolhido por ser eficiente com coleções pequenas.
Última edição: