====== Diego Pereira Nogueira da Silva ======
{{:bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:20180803_090049_1_.jpg?200|}}
Mestrando pelo Departamento de Fisiologia (IB-USP)
O título de minha dissertação é: "Análise do comportamento de rã touro (//Lithobates catesbeianus//): personalidade, síndromes comportamentais e efeito da exposição crônica ao estresse térmico sobre o comportamento", sob orientação do Prof. Dr. Fernando Ribeiro Gomes.
----
----
===== Meus Exercícios =====
No link: [[.:Exercícios - Diego Pereira]]
----
----
===== Proposta de Trabalho Final =====
----
==== Proposta A: Uma função que calcule os valores individuais (IVs) de seus Pokémon ====
----
**Contextualização:**
Pokémon (também conhecidos como Pocket Monsters, “monstros de bolso”, em Português), é uma antiga franquia de domínio da Nintendo. Criada por Satoshi Tajiri em 1996, inicialmente tratava-se apenas de um jogo de Game Boy, o qual possuía duas versões, conhecidas como Pokémon Red e Pokémon Blue.
A franquia cresceu muito nos últimos 23 anos, com a criação, além dos jogos, também de um mangá e uma série animada. Ademais, atualmente somam-se 809 espécies Pokémon descritas, as quais podem ser acessadas em um [[https://bulbapedia.bulbagarden.net/wiki/List_of_Pok%C3%A9mon|acervo virtual]] (devidamente categorizadas pelos seus atributos físicos, distribuição populacional, dentre outras características de interesse), partindo-se de uma descrição de apenas 151 espécies, um grande avanço para os taxônomos do grupo.
{{ :bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:pik.png |}}
//À esquerda, Pika electricus (Tajiri, 1996), também conhecido como Pikachu). À direita: Outra espécie de roedor também popularmente conhecida como Pika (Ochotona sp.), não confundir.//
Porém, em todas as diferentes mídias, a ideia geral se mantém a mesma. Na animação e no mangá, acompanhamos a vida de diversos treinadores Pokémon. Esse treinadores são pessoas que saem a campo para capturar diversos Pokémon selvagens, treiná-los e usá-los em batalhas. Pode parecer algo horrível e cruel para um telespectador desavisado, porém, na maioria dos casos, os Pokémon são muito bem cuidados e escolhem ir com o treinador por vontade própria.
Nos jogos, a grande diferença se dá no fato de que o até então telespectador tem a capacidade de se tornar um treinador de Pokémon, graças a uma interface interativa. Esses treinadores se dividem em diversos tipos: desde os mais casuais aos mais competitivos, os quais buscam os melhores Pokémon possíveis para completarem seus times, de forma a terem uma pequena, porém signficativa, vantagem em suas batalhas. Dentre as mecânicas que os jogadores competitivos utilizam, é possível destacar a seleção de Pokémon com base nos Valores Individuais (IV) de cada um dos seus atributos (Vida, Ataque, Defesa, Ataque Especial, Defesa Especial e Velocidade), segundo as fórmulas:
{{ :bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:hpstatcalcgen34.png |}}
{{ :bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:otherstatcalcgen34.png |}}
Para tal, esses treinadores utilizam-se de diversos programas para descobrirem os IVs de seus Pokémon, de forma a saber se eles estão aptos à entrarem em batalhas competitivas, a função proposta visa auxiliar neste processo.
----
**Planejamento da Função:**
Entrada: ''iv.calc(pokemon, stats, EV = c(0, 0, 0, 0, 0, 0), lvl, nature = "Hardy", database = base.stats)''
* ''database'' = base stats para cada Pokémon que entrarão na fórmula posta acima (Base). //[class: dataframe, [,1] = character, [,(2:7)] = integer]//
__//Para 1 Pokémon//__
* ''pokemon'' = espécie de Pokémon de interesse para cálculo dos IVs, conforme uma lista com 809 espécies, além de suas variações (e.g.: Mega Charizard, Alola Sandshrew). //[class: character]//
* ''stats'' = vetor numérico contendo 6 valores (um para cada atributo do Pokémon, devem vir na ordem correta (HP, ATK, DEF, Sp.A, Sp.D, SPD) para evitar erros futuros. //[class: integer, 1 ≤ stats ≤ 255]//
* ''EV'' = vetor numérico contendo 6 valores referente ao valor de esforço para cada atributo do Pokémon de interesse, devem vir na ordem correta (HP, ATK, DEF, Sp.A, Sp.D, SPD) para evitar erros futuros. //[class: integer, 0 ≤ EV ≤ 255, sum(EV) ≤ 510]//
* ''lvl'' = nível do Pokémon de interesse. //[class: integer, 1 ≤ lvl ≤ 100]//
* ''nature'' = natureza do pokémon, sendo que elas podem ser positivas, neutras ou negativas para cada atributo, adicionando um multiplicador de 1.1, 1 ou 0.9, respectivamente. //[class: factor]//
__//Para diversos Pokémon//__
* ''pokemon'' = coluna de um dataframe com n Pokémon. //[class: character]//
* ''stats'' = seis colunas de um dataframe com n Pokémon. //[class: integer, 1 ≤ stats ≤ 255]//
* ''EV'' = seis colunas de um dataframe com n Pokémon. //[class: integer, 0 ≤ EV ≤ 255, sum(EV) ≤ 510]//
* ''lvl'' = coluna de um dataframe com n Pokémon. //[class: integer, 1 ≤ lvl ≤ 100]//
* ''nature'' = coluna de um dataframe com n Pokémon. //[class: factor]//
----
**Verificando os parâmetros:**
* ''pokemon'' contém apenas nomes de Pokémon que constam no database? Se não:
* //1 Pokémon//: stop(“Esse Pokémon parece não existir, verifique se digitou corretamente”)
* //Dataframe//: warning(“Algumas linhas não rodaram conforme o esperado, verifique se o nome do Pokémon foi digitado corretamente”)
* ''stats'', ''lvl'' e ''EV'' contém apenas números inteiros dentro de suas respectivas delimitações (acima)? Se não:
* //1 Pokémon//: stop(“A variável X deve ser um número inteiro ente Y e Z”)
* //Dataframe//: warning(“Algumas linhas não rodaram conforme o esperado. A variável X deve ser um número inteiro entre Y e Z. Verifique se digitou corretamente”)
* ''stats'' fornecidos condizem com os possíveis atributos para aquele Pokémon, segundo as fórmulas acima? (IMPORTANTE: 0 ≤ IV ≤ 31). Se não:
* //1 Pokémon//: stop(“Os valores fornecidos são impossíveis! Verifique se os atributos, EVs, nível e natureza estão corretos”)
* //Dataframe//: warning(“Algumas linhas contêm valores impossíveis! Verifique se os atributos, EVs, níveis e naturezas estão corretos”)
* ''stats'' e ''EV'' possuem os tamanhos apropriados? Se não:
* //1 Pokémon//: stop(“O vetor stats deve conter 6 valores inteiros”)
* //Dataframe//: stop(“O vetor stats deve conter 6 colunas de um dataframe”)
* ''nature'' condiz com as 25 possíveis naturezas para os Pokémon? Se não:
* //1 Pokémon//: stop(“A natureza fornecida não existe, verifique se digitou corretamente”)
* //Dataframe//: warning(“Algumas linhas não rodaram conforme o esperado. Verifique se as naturezas fornecidas estão corretas”)
* ''database'' é um data frame contendo 7 colunas, sendo a primeira coluna caracteres e as demais valores inteiros? Se não: stop(“Parece haver algum problema com seu database”)
----
**Pseudo-código:**
- Verifica se o objeto ''base.stats'' existe, se sim, usa ele como database, se não, cria o database a partir de um arquivo que estará na internet. __#Isso permite com que o usuário faça alterações no database, caso queira__;
- Verifica se os valores fornecidos são um vetor ou dataframe;
- Cria o objeto ''valores.iv'' aplicando a fórmula fornecida e arredondando para o valor inteiro mais próximo;
- Cria o objeto ''valores.iv.spread'' aplicando a fórmula, simulando quais valores de IV (de 0 a 31), gerariam o mesmo valor para o atributo observado. __#Isso é importante pois quanto menor o nível do Pokémon, menor a variação nos seus atributos. Ou seja, quanto menor o nível do Pokémon, mais impreciso é o cálculo dos IVs__;
- Para tal, cria-se um ciclo ''for'' com contador ''IV'' de 0 a 31;
- Aplica-se a fórmula dentro do ciclo for, tomando como base para o atributo o valor que foi fornecido pelo usuário;
- O range dos valores de IV que atingirem o mesmo valor do atributo são salvos no objeto ''valores.iv.spread'' e fecha-se o ciclo.
----
**Saída:**
Será retornado: ''valores.iv'', ''valores.iv.spread''
Caso o objeto de entrada seja um vetor, os valores de saída serão vetores. Tal qual, caso a entrada seja um dataframe, os valores de saída também serão um dataframe.
----
----
----
==== Proposta B: Criando um jogo de Escape Room ====
----
**Contextualização:**
Escape Room é um gênero de jogos onde o objetivo do jogador é resolver uma série de puzzles e/ou tomar decisões lógicas com o objetivo de escapar de uma sala/situação qualquer. Embora a ideia original seja mais antiga, o gênero se popularizou no meio flash em 2004 com o point-and-click entitulado Crimson Room, de Toshimitsu Takagi.
{{ :bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:crimsom.jpg |}}
//Crimson Room de Toshimitsu Takagi, se você foi criança nos anos 90/2000, você provavelmente o conhece.//
Tal qual programar, jogos Escape Room podem ser bastante frustrantes inicialmente. Porém, a satisfação de chegar ao fim muitas vezes é tão boa quanto a sensação de um código que funciona. Dessa forma, minha proposta B visa criar um jogo Escape Room que seja puramente text-based, em linguagem R.
----
**Planejamento da função:**
Entrada: ''escape(idioma = pt, dificuldade = normal)''
* ''idioma'' = permite o usuário alterar o idioma do jogo //[class: character]//
* ''nivel'' = permite o usuário selecionar a dificuldade do jogo //[class: character]//
__#Sendo um jogo, os parâmetros apenas definem o que seriam as configurações. Uma vez iniciada a função, ela aguardaria demais inputs do usuário.__
----
**Verificando os parâmetros:**
''idioma'' condiz com um dos idiomas disponíveis? Se não: warning(“O idioma selecionado não condiz com as opções disponíveis no momento. Iniciando o jogo em português.”)
''dificuldade'' condiz com uma das dificuldades disponíveis? Se não: warning(“A dificuldade selecionada não condiz com as opções disponíveis no momento. Iniciando o jogo na dificuldade normal”)
----
**Pseudo-código:**
- Instala o pacote dplyr e dependências caso não esteja instalado
- ''library(dplyr)''
- Com a função ''case_when'' (pacote dplyr), cria a história do jogo e as diversas opções que o jogador pode tomar, as quais aparecerão no console com a função ''readline'', permitindo que o jogador interaja e tome decisões.
----
**Saída:**
Caso o jogador perca, retorna mensagem de GAME OVER. Caso vença, uma mensagem de vitória.
----
----
===== Trabalho Final =====
**Proposta escolhida: A - Calculadora de Valores Individuais de Pokémon**
----
==== Database (arquivo necessário para rodar a função) ====
{{:bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:base.stats.csv|base.stats}}
A função automaticamente irá baixar o database a partir deste link.
----
==== Arquivo da função ====
{{:bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:iv.calc.r|}}
----
==== Arquivo do help ====
{{:bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:help.iv.calc.txt|}}
----
==== Código da função ====
#Iniciando a função e definindo os parâmetros, tais quais seus valores padrão.
iv.calc = function(pokemon, stats, EV, lvl, nature = "Hardy", interesse = NULL, database = base.stats)
{
#Lança a seguinte mensagem na tela, falando sobre a função e sobre como usá-la corretamente.
cat("ATENÇÃO! Esta função utiliza os base stats dos Pokémon com base na sétima geração em diante.\nComo padrão, esse database é criado a partir de um link na internet com o nome base.stats\nCaso queira utilizar um database próprio, certifique-se de que:\n1) A primeira coluna do database contém os nomes dos Pokémon;\n2) As demais colunas contêm seus atributos na ordem: HP, ATK, DEF, Sp.A, Sp.D e SPD.\nDo contrário, a função irá gerar resultados errados.\nAdemais, certifique-se também de oferecer os 6 atributos e EVs dos Pokémons nesta mesma ordem.\n\n")
#####################################################
########## Checando e ajustando o database ##########
#####################################################
#Checa se o arquivo padrão "base.stats" existe.
if(exists("base.stats")==FALSE)
{
#Caso o arquivo não exista, cria ele a partir de um link da internet, o argumento "as.is=T" faz com que a função não atribua fatores a caracteres.
base.stats = read.csv(url("http://ecologia.ib.usp.br/bie5782/lib/exe/fetch.php?media=bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:base.stats.csv"), as.is=T)
}
#Caso a pessoa queira fornecer um database com outro nome, checa se este database é um data frame.
if(is.data.frame(database)==FALSE)
{
#Caso não seja, para a função e fornece uma mensagem explicativa.
stop("Database deve ser um data frame.")
}
##################################################
########## Crindo a matriz de naturezas ##########
##################################################
#Cria a matriz de naturezas, com os respectivos valores que vão entrar nas contas mais para frente como multiplicadores.
nat.mat = matrix(c(rep(1, 5),1.1,0.9,1,1,1,1.1,1,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,0.9,1.1,1,1,1,rep(1, 5),1,1.1,0.9,1,1,1,1.1,1,0.9,1,1,1.1,1,1,0.9,0.9,1,1.1,1,1,1,0.9,1.1,1,1,rep(1, 5),1,1,1.1,0.9,1,1,1,1.1,1,0.9,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,1.1,1,rep(1, 5),1,1,1,1.1,0.9,0.9,1,1,1,1.1,1,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,1.1,rep(1, 5)),
#Define que a matriz tem 5 colunas e que deve ser preenchida por linhas.
ncol=5, byrow=T,
#Adiciona os nomes das linhas (naturezas) e colunas (atributos) da matriz.
dimnames=list(c("Hardy","Lonely","Adamant","Naughty","Brave","Bold","Docile","Impish","Lax","Relaxed","Modest","Mild","Bashful","Rash","Quiet","Calm","Gentle","Careful","Quirky","Sassy","Timid","Hasty","Jolly","Naive","Serious"), c("ATK","DEF","Sp.A","Sp.D","SPD")))
################################################
########## Definindo critérios gerais ##########
################################################
#Checa os valores do parâmetro "stats".
if(any(stats < 1) | any(stats > 714))
{
#Caso os valores ultrapassem os limites perimitidos, para a função e fornece uma mensagem explicativa.
stop("Os valores dos atributos devem ser números inteiros entre 1 e 714. Pelo menos um dos atributos está fora do limite.")
}
#Checa os valores do parâmetro "EV".
if(any(EV < 0 | EV > 252))
{
#Caso os valores ultrapassem os limites perimitidos, para a função e fornece uma mensagem explicativa.
stop("Os valores de EVs devem ser números inteiros entre 0 e 252. Pelo menos um dos EVs está fora do limite.")
}
############################################
########## Para apenas um pokémon ##########
############################################
#Checa se o usuário forneceu apenas um pokémon.
if(length(pokemon)==1)
{
#Em caso positivo, checa se "stats" e "EV" são vetores.
if(is.vector(stats)==FALSE | is.vector(EV)==FALSE)
{
#Caso não sejam, para a função e fornece uma mensagem explicativa.
stop("Os atributos e EVs devem ser um vetor numérico.")
}
#Checa se o pokémon fornecido existe no database.
if(pokemon%in%database[,1]==FALSE)
{
#Caso não, para a função e fornece uma mensagem explicativa.
stop("Esse Pokémon não consta no database.\nVerifique se digitou corretamente.")
}
#Checa se o parâmetro "lvl" está dentro dos limites permitidos.
if(lvl < 1 | lvl > 100)
{
#Caso o valor ultrapasse os limites perimitidos, para a função e fornece uma mensagem explicativa.
stop("O nível de um Pokémon deve ser um número inteiro entre 1 e 100.")
}
#Checa se a soma dos EVs está dentro do limite permitido.
if(sum(EV) > 510)
{
#Caso os valores ultrapassem os limites perimitidos, para a função e fornece uma mensagem explicativa.
stop("A soma dos EVs de um Pokémon não deve ultrapassar 510.")
}
#Checa se a natureza fornecida corresponde com as naturezas existentes.
if(nature%in%rownames(nat.mat)==FALSE)
{
#Caso não, para a função e fornece uma mensagem explicativa.
stop("A natureza fornecida não corresponde com uma das 25 naturezas possíveis.\nVerifique se digitou corretamente.")
}
#Cria os objetos HPs, ATKs, DEFs, Sp.As, Sp.Ds e SPDs, contendo apenas 32 NAs (pois os IVs podem ter 32 valores possíveis).
HPs = ATKs = DEFs = Sp.As = Sp.Ds = SPDs = rep(NA, 32)
#Inicia um for para preencher os objetos acima com os valores dos stats que correspondem ao IV do pokémon, para aquele nível, EVs e natureza.
for(i in 1:32)
{
#Preenche o objeto HPs com a respectiva fórmula para cálculo do HP do pokémon fornecido, onde "(i-1)" corresponde ao IV, que vai de 0 a 31. Arredondado para valores inteiros.
HPs[i] = round(((2*database[database[,1]==pokemon,2] + (i-1) + EV[1]/4 + 100) * lvl) / 100 + 10)
ATKs[i] = round((((2*database[database[,1]==pokemon,3] + (i-1) + EV[2]/4) * lvl) / 100 + 5) * nat.mat[nature,1]) #Idem acima, só que para o atributo ATK.
DEFs[i] = round((((2*database[database[,1]==pokemon,4] + (i-1) + EV[3]/4) * lvl) / 100 + 5) * nat.mat[nature,2]) #Idem acima, só que para o atributo DEF.
Sp.As[i] = round((((2*database[database[,1]==pokemon,5] + (i-1) + EV[4]/4) * lvl) / 100 + 5) * nat.mat[nature,3]) #Idem acima, só que para o atributo Sp.A.
Sp.Ds[i] = round((((2*database[database[,1]==pokemon,6] + (i-1) + EV[5]/4) * lvl) / 100 + 5) * nat.mat[nature,4]) #Idem acima, só que para o atributo Sp.D.
SPDs[i] = round((((2*database[database[,1]==pokemon,7] + (i-1) + EV[6]/4) * lvl) / 100 + 5) * nat.mat[nature,5]) #Idem acima, só que para o atributo SPD.
}
#Cria o spread do atributo HP daquele pokémon fornecido, selecionando quais valores do objeto HPs criado acima correspondem ao HP fornecido pelo usuário em "stats".
spread.HP = which(HPs==stats[1])
spread.ATK = which(ATKs==stats[2]) #Idem acima, só que para o atributo ATK.
spread.DEF = which(DEFs==stats[3]) #Idem acima, só que para o atributo DEF.
spread.Sp.A = which(Sp.As==stats[4]) #Idem acima, só que para o atributo Sp.A.
spread.Sp.D = which(Sp.Ds==stats[5]) #Idem acima, só que para o atributo Sp.D.
spread.SPD = which(SPDs==stats[6]) #Idem acima, só que para o atributo SPD.
#Calcula o IV daquele pokémon fornecido para o atributo HP, o qual corresponde à mediana do spread, arredondado para valores inteiros.
iv.HP = round(median(spread.HP))
iv.ATK = round(median(spread.ATK)) #Idem acima, só que para o atributo ATK.
iv.DEF = round(median(spread.DEF)) #Idem acima, só que para o atributo DEF.
iv.Sp.A = round(median(spread.Sp.A)) #Idem acima, só que para o atributo Sp.A.
iv.Sp.D = round(median(spread.Sp.D)) #Idem acima, só que para o atributo Sp.D.
iv.SPD = round(median(spread.SPD)) #Idem acima, só que para o atributo SPD.
#Cria o objeto valores IV, que corresponde a um data frame com os valores acima.
valores.iv = c(iv.HP, iv.ATK, iv.DEF, iv.Sp.A, iv.Sp.D, iv.SPD)
#Verifica se os valores do objeto "valores.iv" estão corretos (caso o IV calculado seja menor que 0 ou maior que 31, a função gera um NA, isso ocorre caso o usuário forneça parâmetros errados).
if(NA%in%valores.iv==TRUE)
{
#Caso o objeto contenha NAs, prossegue a função, mas fornece uma mensagem de aviso, indicando que algum parâmetro fornecido estava incorreto.
warning("Os parâmetros oferecidos geraram valores impossíveis de IV (1 <= IV <= 31).\nVerifique se a natureza e os valores dos atributos, EVs e nível estão corretos.")
}
#Adiciona nomes ao vetor "valores.iv".
names(valores.iv) = c("HP", "ATK", "DEF", "Sp.A", "Sp.D", "SPD")
#Retorna os objetos referente aos IVs dos pokémon e seus spreads, em uma lista.
return(list("IVs Medianos" = valores.iv, "IV Spread - HP" = spread.HP, "IV Spread - ATK" = spread.ATK, "IV Spread - DEF" = spread.DEF, "IV Spread - Sp.A" = spread.Sp.A, "IV Spread - Sp.D" = spread.Sp.D, "IV Spread - SPD" = spread.SPD))
}
#########################################
########## Para vários pokémon ##########
#########################################
#Checa se o usuário forneceu mais de um pokémon.
if(length(pokemon)>1)
{
#Em caso positivo, checa se "stats" e "EV" são data frames.
if(is.data.frame(stats)==FALSE | is.data.frame(EV)==FALSE)
{
#Caso não, para a função e fornece uma mensagem explicativa.
stop("Os atributos e EVs devem ser um data frame.")
}
#Checa se algum dos pokémon fornecido não consta no database.
if(any(pokemon%in%database[,1]==FALSE))
{
#Caso algum pokémon não conste no database, para a função e fornece uma mensagem explicativa.
stop("Pelo menos um Pokémon não consta no database.\nVerifique se digitou corretamente.")
}
#Checa se os níveis dos pokémon estão dentro do limite permitido.
if(any(lvl < 1 | lvl > 100))
{
#Caso algum valor ultrapasse o limite, para a função e fornece uma mensagem explicativa.
stop("O nível de um Pokémon deve ser um número inteiro entre 1 e 100.\nO nível de pelo menos um dos Pokémon está fora do limite.")
}
#Checa se a soma dos EVs de cada pokémon (linha) está dentro do limite permitido.
if(any(apply(EV, 1, sum) > 510))
{
#Caso algum valor ultrapasse o limite, para a função e fornece uma mensagem explicativa.
stop("A soma dos EVs de um Pokémon não deve ultrapassar 510.")
}
#Checa se alguma das naturezas fornecidas não consta na matriz de naturezas.
if(any(nature%in%rownames(nat.mat)==FALSE))
{
#Em caso positivo, para a função e fornece uma mensagem explicativa.
stop("Pelo menos uma das naturezas fornecida não corresponde com uma das 25 naturezas possíveis.\nVerifique se digitou corretamente.")
}
#Cria os objetos HPs, ATKs, DEFs, Sp.As, Sp.Ds e SPDs, os quais são matrizes com 32 colunas (pois os IVs podem ter 32 valores possíveis) e tantas linhas quanto o usuário fornecer de pokémon.
HPs = ATKs = DEFs = Sp.As = Sp.Ds = SPDs = matrix(rep(NA, length(pokemon)*32), ncol=32)
#Inicia um for para preencher os objetos acima com os valores dos stats que correspondem ao IV do pokémon, para aquele nível, EVs e natureza.
for(j in 1:32) #1:32 corresponde ao número de colunas.
{
#Inicia um segundo for, pois trata-se de um objeto bidimensional.
for(i in 1:length(pokemon)) #1:length(pokemon)) corresponde ao número de linhas.
{
#Preenche o objeto HPs com a respectiva fórmula para cálculo do HP do pokémon fornecido, onde "(j-1)" corresponde ao IV, que vai de 0 a 31. Arredondado para valores inteiros.
HPs[i,j] = round(((2*database[database[,1]==pokemon[i],2] + (j-1) + EV[i,1]/4 + 100) * lvl[i]) / 100 + 10)
ATKs[i,j] = round((((2*database[database[,1]==pokemon[i],3] + (j-1) + EV[i,2]/4) * lvl[i]) / 100 + 5) * nat.mat[nature[i],1]) #Idem acima, só que para o atributo ATK.
DEFs[i,j] = round((((2*database[database[,1]==pokemon[i],4] + (j-1) + EV[i,3]/4) * lvl[i]) / 100 + 5) * nat.mat[nature[i],2]) #Idem acima, só que para o atributo DEF.
Sp.As[i,j] = round((((2*database[database[,1]==pokemon[i],5] + (j-1) + EV[i,4]/4) * lvl[i]) / 100 + 5) * nat.mat[nature[i],3]) #Idem acima, só que para o atributo Sp.A.
Sp.Ds[i,j] = round((((2*database[database[,1]==pokemon[i],6] + (j-1) + EV[i,5]/4) * lvl[i]) / 100 + 5) * nat.mat[nature[i],4]) #Idem acima, só que para o atributo Sp.D.
SPDs[i,j] = round((((2*database[database[,1]==pokemon[i],7] + (j-1) + EV[i,6]/4) * lvl[i]) / 100 + 5) * nat.mat[nature[i],5]) #Idem acima, só que para o atributo SPD.
}
}
#Cria os objetos referentes aos spreads, os quais são n (length(pokemon)) listas vazias.
spread.HP = spread.ATK = spread.DEF = spread.Sp.A = spread.Sp.D = spread.SPD = rep(list(NA),length(pokemon))
#Cria os objetos referentes aos ivs dos pokémon, os quais são vetores contendo length(pokemon) NAs.
iv.HP = iv.ATK = iv.DEF = iv.Sp.A = iv.Sp.D = iv.SPD = rep(NA, length(pokemon))
#Inicia um for para preencher os objetos acima com seus valores.
for(i in 1:length(pokemon))
{
#Preenche o spread do atributo HP daqueles pokémon fornecido, selecionando quais valores do objeto HPs criado acima correspondem ao HP fornecido pelo usuário em "stats".
spread.HP[[i]] = which(HPs[i,]==stats[i,1])
spread.ATK[[i]] = which(ATKs[i,]==stats[i,2]) #Idem acima só que para o atributo ATK.
spread.DEF[[i]] = which(DEFs[i,]==stats[i,3]) #Idem acima só que para o atributo DEF.
spread.Sp.A[[i]] = which(Sp.As[i,]==stats[i,4]) #Idem acima só que para o atributo Sp.A.
spread.Sp.D[[i]] = which(Sp.Ds[i,]==stats[i,5]) #Idem acima só que para o atributo Sp.D.
spread.SPD[[i]] = which(SPDs[i,]==stats[i,6]) #Idem acima só que para o atributo SPD.
#Calcula o IV daqueles pokémon fornecido para o atributo HP, o qual corresponde à mediana do spread, arredondado para valores inteiros.
iv.HP[i] = round(median(spread.HP[[i]]))
iv.ATK[i] = round(median(spread.ATK[[i]])) #Idem acima só que para o atributo ATK.
iv.DEF[i] = round(median(spread.DEF[[i]])) #Idem acima só que para o atributo DEF.
iv.Sp.A[i] = round(median(spread.Sp.A[[i]])) #Idem acima só que para o atributo Sp.A.
iv.Sp.D[i] = round(median(spread.Sp.D[[i]])) #Idem acima só que para o atributo Sp.D.
iv.SPD[i] = round(median(spread.SPD[[i]])) #Idem acima só que para o atributo SPD.
}
#Cria o objeto "valores.iv", um data frame de 6 colunas, uma para cada um dos atributos calculados acima.
valores.iv = data.frame(Pokémon = pokemon, HP = iv.HP, ATK = iv.ATK, DEF = iv.DEF, Sp.A = iv.Sp.A, Sp.D = iv.Sp.D, SPD = iv.SPD)
#Verifica se os valores do objeto "valores.iv" estão corretos (caso o IV calculado seja menor que 0 ou maior que 31, a função gera um NA, isso ocorre caso o usuário forneça parâmetros errados).
if(is.na(any(valores.iv==TRUE)))
{
#Caso o objeto contenha NAs, prossegue a função, mas fornece uma mensagem de aviso, indicando que algum parâmetro fornecido estava incorreto.
warning("Os parâmetros oferecidos geraram valores impossíveis de IV (1 <= IV <= 31).\nVerifique se a natureza e os valores dos atributos, EVs e nível estão corretos.")
}
#Cria o objeto "temp", um arquivo temporário para os passos seguintes, que corresponde ao objeto valores.iv, menos a primeira coluna.
temp = valores.iv[,-1]
#Checa se o usuário forneceu um pokémon de interesse nos parâmetros.
if(is.null(interesse))
{
#Em caso negativo, cria um stripchart com os seguintes parâmetros abaixo.
stripchart(x=temp, #Valores de temp.
vertical=T, #Na vertical.
method="jitter", jitter=0.2, #Utilizando o método jitter, com 0.2 de valor de jitter.
cex=1.1, cex.lab=1.5, cex.axis=1.1, #Aumenta os tamanhos dos pontos, da legenda e dos valores dos eixos, respectivamente.
pch=19, #Define o tipo de ponto do gráfico.
ylim=c(-2,33), xlim=c(0.5,6.5), #Define os limites de x e y.
ylab="Valores Individuais", #Define a legenda do eixo y.
tck=0.01, #Define o tamanho dos tiques nos eixos.
las=1, #Define a orientação do eixo.
family="sans", #Define a fonte dos elementos do gráfico.
mgp=c(2.3,0.3,0), #Define as distâncias da legenda, dos valores dos eixos e do eixo.
col=c("firebrick1","darkorange","goldenrod1","dodgerblue","limegreen","hotpink")) #Define as cores para os diferentes atributos dos pokémon.
#Cria uma linha tracejada verde, com width=3, na altura 26 do eixo y, correspondente a IVs considerado "muito bons".
abline(26,0, col="green3", lty=3, lwd=3)
#Retorna os objetos referente aos IVs dos pokémon e seus spreads, em uma lista.
return(list("IVs Medianos" = valores.iv, "IV Spread - HP" = spread.HP, "IV Spread - ATK" = spread.ATK, "IV Spread - DEF" = spread.DEF, "IV Spread - Sp.A" = spread.Sp.A, "IV Spread - Sp.D" = spread.Sp.D, "IV Spread - SPD" = spread.SPD))
}
#Caso o usuário tenha fornecido um pokémon de interesse.
else
{
#Cria o mesmo gráfico acima, com os mesmos parâmetros, exceto removendo o pokémon de interesse dos valores plotados (x=temp[-interesse,]).
stripchart(x=temp[-interesse,], vertical=T, method="jitter", jitter=0.2, cex=1.1, cex.lab=1.5, cex.axis=1.1, pch=19, ylim=c(-2,33), ylab="Valores Individuais", tck=0.01, las=1, family="sans", mgp=c(2.3,0.3,0), col=c("firebrick1","darkorange","goldenrod1","deepskyblue","limegreen","hotpink"))
#Cria a mesma linha acima, correspondente a IVs considerado "muiton bons".
abline(26,0, col="green3", lty=3, lwd=3)
#Plota os valores referentes ao pokémon de interesse, com formato (pch), tamanho (cex) e cor diferentes dos demais pokémon do gráfico.
points(x=c(1:6), y=temp[interesse,], pch=17, cex=1.5)
#Plota o intervalo de erro (spread) para o IV do pokémon de interesse referente a HP.
segments(x0 = 1, y0 = min(unlist(c(spread.HP[[interesse]]))), x1 = 1, y1 = max(unlist(spread.HP[[interesse]])), lwd=2)
segments(x0 = 2, y0 = min(unlist(spread.ATK[[interesse]])), x1 = 2, y1 = max(unlist(spread.ATK[[interesse]])), lwd=2) #Idem acima, só que para o atributo ATK.
segments(x0 = 3, y0 = min(unlist(spread.DEF[[interesse]])), x1 = 3, y1 = max(unlist(spread.DEF[[interesse]])), lwd=2) #Idem acima, só que para o atributo DEF.
segments(x0 = 4, y0 = min(unlist(spread.Sp.A[[interesse]])), x1 = 4, y1 = max(unlist(spread.Sp.A[[interesse]])), lwd=2) #Idem acima, só que para o atributo Sp.A.
segments(x0 = 5, y0 = min(unlist(spread.Sp.D[[interesse]])), x1 = 5, y1 = max(unlist(spread.Sp.D[[interesse]])), lwd=2) #Idem acima, só que para o atributo Sp.D.
segments(x0 = 6, y0 = min(unlist(spread.SPD[[interesse]])), x1 = 6, y1 = max(unlist(spread.SPD[[interesse]])), lwd=2) #Idem acima, só que para o atributo SPD.
#Plota o nome daquele pokémon ao lado dos seus respectivos valores no gráfico.
text(x=c((1:6)-.05), y=temp[interesse,]+0.5, labels=rep(pokemon[interesse], 6), pos=4, cex=0.7)
#Cria o objeto "ivmaior", uma lista contendo os pokémon que tenham IVs maiores do que o pokémon de interesse para cada um dos atributos.
ivmaior = list(HP = which(temp[,1] > temp[interesse,1]), ATK = which(temp[,2] > temp[interesse,2]), DEF = which(temp[,3] > temp[interesse,3]), Sp.A = which(temp[,4] > temp[interesse,4]), Sp.D = which(temp[,5] > temp[interesse,5]), SPD = which(temp[,6] > temp[interesse,6]))
#Cria o objeto "ivmenor", uma lista contendo os pokémon que tenham IVs maiores do que o pokémon de interesse para cada um dos atributos.
ivmenor = list(HP = which(temp[,1] < temp[interesse,1]), ATK = which(temp[,2] < temp[interesse,2]), DEF = which(temp[,3] < temp[interesse,3]), Sp.A = which(temp[,4] < temp[interesse,4]), Sp.D = which(temp[,5] < temp[interesse,5]), SPD = which(temp[,6] < temp[interesse,6]))
#Cria o objeto "ivspread", uma lista contendo os pokémon cujos IV estejam dentro do intervalo de erro (spread) do pokémon de interesse.
ivspread = list(HP = which(temp[,1] <= max(unlist(spread.HP[[interesse]])) & temp[,1] >= min(unlist(spread.HP[[interesse]]))), #Cria a lista para o spread de HP.
ATK = which(temp[,2] <= max(unlist(spread.ATK[[interesse]])) & temp[,2] >= min(unlist(spread.ATK[[interesse]]))), #Cria a lista para o spread de ATK.
DEF = which(temp[,3] <= max(unlist(spread.DEF[[interesse]])) & temp[,3] >= min(unlist(spread.DEF[[interesse]]))), #Cria a lista para o spread de DEF.
Sp.A = which(temp[,4] <= max(unlist(spread.Sp.A[[interesse]])) & temp[,4] >= min(unlist(spread.Sp.A[[interesse]]))), #Cria a lista para o spread de Sp.A.
Sp.D = which(temp[,5] <= max(unlist(spread.Sp.D[[interesse]])) & temp[,5] >= min(unlist(spread.Sp.D[[interesse]]))), #Cria a lista para o spread de Sp.D.
SPD = which(temp[,6] <= max(unlist(spread.SPD[[interesse]])) & temp[,6] >= min(unlist(spread.SPD[[interesse]])))) #Cria a lista para o spread de SPD.
#Retorna os objetos valores.iv, ivmaior, ivmenor e ivspread, em uma lista.
return(list("IVs Medianos" = valores.iv, "IVs Maiores" = ivmaior, "IVs Menores" = ivmenor, "IVs em Spread" = ivspread))
}
}
}
----
==== Código do help ====
iv.calc package:unknown R Documentation
~~Calculadora de Valores Individuais (Pokémon)~~
Descrição:
~~ iv.calc é uma função criada para calcular os valores individuais (IVS) de seus pokémon dos jogos da geração III ~~
~~ em diante. Como padrão, a função usa os valores base (database) da geração VII em diante. ~~
~~ Não funciona para o Pokémon GO. ~~
Uso:
~~ iv.calc(pokemon, stats, EV, lvl, nature = "Hardy", interesse = NULL, database = base.stats) ~~
Arguments:
~~ pokemon O nome de pokémon que deseja calcular o IV. Deve vir escrito exatamente como consta o nome do ~~
~~ pokémon no database. Pode ser um valor único ou um vetor contendo o nome de n pokémon. ~~
~~ stats Os valores dos atributos de seus pokémon, na ordem: HP, ATK, DEF, Sp.A, Sp.D e SPD. ~~
~~ Pode ser um vetor contendo apenas esses 6 valores, ou um data.frame contendo 6 colunas e n linhas ~~
~~ equivalentes a cada pokémon [1 <= stats <= 714]. ~~
~~ EV Os EVs ou valores de esforço de seus pokémon, na ordem: HP, ATK, DEF, Sp.A, Sp.D e SPD. ~~
~~ Pode ser um vetor contendo apenas esses 6 valores, ou um data.frame contendo 6 colunas e n linhas ~~
~~ equivalentes a cada pokémon [0 <= EV <= 252; sum(EV) < 510]. ~~
~~ lvl O nível de seus pokémon. Pode ser um valor único ou um vetor contendo os níveis de n pokémon. ~~
~~ [1 <= lvl <= 100]. ~~
~~ nature A natureza de seus pokémon. Deve vir escrita da seguinte forma: "Hardy","Bashful","Adamant", etc. ~~
~~ Também deve conter apenas os nomes das 25 possíveis naturezas dos pokémon. Pode ser um valor único ~~
~~ ou um vetor contendo as naturezas de n pokémon. ~~
~~ interesse Dados vários pokémon (n > 1), o usuário pode escolher um pokémon de interesse em ~~
~~ particular para ser comparado com os demais pokémon em relação a seus IVs. Deve ser um número inteiro ~~
~~ único de 1 a n, correspondente a posição do pokémon de interesse no vetor pokemon. ~~
~~ database Um dataframe contendo 7 colunas, sendo a primeira coluna o nome de todos os Pokémon e as demais ~~
~~ colunas seus atributos basais, utilizados no cálculo dos IVs, na ordem HP, ATK, DEF, Sp.A, Sp.D e SPD. ~~
~~ Caso o usuário não forneça um database, ele é baixado diretamente da internet. ~~
Detalhes:
~~ Fórmulas usadas nessa função: ~~
~~ Cálculo do HP: HP = ((2*ValorBasal + IV + EV/4 + 100) * Nível) / 100 + 10 ~~
~~ Cálculo dos demais atributos: Atributo = (((2*ValorBasal + IV + EV/4) * Nível) / 100 + 5) * Natureza ~~
~~ Caso o usuário forneça valores errados para stats, lvl, EV ou nature, a função irá rodar, porém, poderão ser ~~
~~ criados valores impossíveis de IV impossíveis (0 <= IV <= 31). Nesse caso, o usuário receberá um aviso e a saída ~~
~~ conterá NAs e listas vazias. ~~
~~ Os valores de stats variam de 1 a 714 pois esses são o menor e maior valor que um pokémon pode ter. ~~
~~ Shedinja sempre possui 1 de HP e uma Blissey com 31 de IV e 252 de EVs pode atingir 714 HP. ~~
~~ Por esse motivo, caso os valores ultrapassem esse limite, escolhi que a função parasse automaticamente, ~~
~~ evitando a criação de NAs mais para frente. ~~
~~ As natureza dos pokémon entram na fórmula na forma de um multiplicador que pode assumir os valores 1.1, 1 ou 0.9 ~~
~~ caso elas sejam respectivamente, "positivas", "neutras" ou "negativa" para determinado atributo. ~~
~~ Por ser uma natureza neutra para todos os atributos, "Hardy" foi colocada como padrão para a função. ~~
~~ Além de calcular os IVs dos pokémon, a função também calcula o spread de seus IVs. Isto é, os valores de IV ~~
~~ que gerariam um valor igual ao valor do atributo do pokémon quando arredondado para zero casas decimais. ~~
~~ Isso ocorre pois a fórmula do cálculo dos IVs gera números reais, porém os IVs podem apenas ser números inteiros. ~~
~~ Ademais, dadas as fórmulas, quanto menor o nível dos pokémon, maior é o erro associado ao cálculo do IV. ~~
~~ Caso sejam fornecidos n > 1 pokémon, a função possui uma saída gráfica (scatterplot), onde os valores dos ~~
~~ IVs de cada atributo são mostrados graficamente, separados pelas cores que eles apresentam nos jogos. ~~
~~ Ademais, a função também adiciona uma linha horizontal referente ao limiar de IVs que é considerado "muito bom" ~~
~~ (IV >= 26). Por fim, caso o usuário forneça um pokémon de interesse em particular, este recebe destaque no gráfico ~~
~~ e também virá com uma barra de erro referente aos valores de spread possível dos seu IVs. ~~
Value:
~~ Retorna uma de duas listas possíveis. ~~
~~ Se pokemon tiver n = 1, ou n > 1 & interesse = NULL ~~
[[1]] IVs Medianos : Um vetor para n = 1 ou um data.frame para n > 1, contendo os IVs de cada um dos pokémon.
[[2]] IV Spread - HP : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de HP de cada um dos pokémon.
[[3]] IV Spread - ATK : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de ATK de cada um dos pokémon.
[[4]] IV Spread - DEF : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de DEF de cada um dos pokémon.
[[5]] IV Spread - Sp.A : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de Sp.A de cada um dos pokémon.
[[6]] IV Spread - Sp.D : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de Sp.D de cada um dos pokémon.
[[7]] IV Spread - SPD : Um vetor para n = 1 ou uma lista para n > 1, contendo o spread para os IVs de SPD de cada um dos pokémon.
~~ Se pokemon tiver n > 1 & interesse != NULL ~~
[[1]] IVs Medianos : Um vetor para n = 1 ou um data.frame para n > 1, contendo os IVs de cada um dos pokémon.
[[2]] IVs maiores : Uma lista com a posição dos pokémon no parâmetro pokemon que possuem os IVs maiores que o pokémon de
interesse em cada um dos atributos.
[[3]] IVs menores : Uma lista com a posição dos pokémon no parâmetro pokemon que possuem os IVs menores que o pokémon de
interesse em cada um dos atributos.
[[4]] IVs em spread : Uma lista com a posição dos pokémon no parâmetro pokemon que possuem os IVs dentro do intervalo de
spread para o pokémon de interesse em cada um dos atributos. (Contém o próprio pokémon de interesse).
Notas:
~~ O objeto de saída pode ficar extremamente poluído para um n grande de pokémon, porém, dada a natureza dos spreads, ~~
~~ os quais são vetores de 0 até 32 posições, não era possível salvá-los em um formato que não lista. ~~
~~ Use a indexação das listas ([[]]) acima para facilitar a vizualição. ~~
Autor:
~~ Diego Pereira Nogueira da Silva ~~
Referências:
~~ Bulbapedia: https://bulbapedia.bulbagarden.net/wiki/Individual_values ~~
Examples:
## Exemplo para 1 pokémon
exemplo = iv.calc(pokemon="Bulbasaur",
stats=c(110,69,60,80,80,50),
EV=c(0,0,0,0,0,0),
lvl=50,
nature="Brave")
## Exemplo para mais de um pokémon e interesse = NULL
exemplo2 = iv.calc(pokemon=c("Bulbasaur","Blissey"),
stats=data.frame(HP=c(110,623),ATK=c(69,51),DEF=c(60,51),Sp.A=c(80,174),Sp.D=c(80,285),SPD=c(50,122)),
EV=data.frame(EVHP=c(0,0),EVATK=c(0,0),EVDEF=c(0,0),EVSp.A=c(0,0),EVSp.D=c(0,0),EVSPD=c(0,0)),
lvl=c(50,100),
nature=c("Brave","Brave"))
## Exemplo para mais de um pokémon de interesse != NULL
exemplo3 = iv.calc(pokemon=c("Bulbasaur","Blissey","Pikachu"),
stats=data.frame(HP=c(110,623,166),ATK=c(69,51,116),DEF=c(60,51,85),
Sp.A=c(80,174,110),Sp.D=c(80,285,111),SPD=c(50,122,189)),
EV=data.frame(EVHP=c(0,0,50),EVATK=c(0,0,50),EVDEF=c(0,0,50),
EVSp.A=c(0,0,50),EVSp.D=c(0,0,50),EVSPD=c(0,0,50)),
lvl=c(50,100,75),
nature=c("Brave","Brave","Hasty"),
interesse=3)
## Exemplo simulando muitos pokémon
a = matrix(round(runif(300,0,31)), ncol=6)
b = data.frame(rep("Articuno",50))
base.stats = read.csv(url("http://ecologia.ib.usp.br/bie5782/lib/exe/fetch.php?media=bie5782:01_curso_atual:alunos:trabalho_final:diego.pereira.silva:base.stats.csv"), as.is=T)
nat.mat = matrix(c(rep(1, 5),1.1,0.9,1,1,1,1.1,1,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,0.9,1.1,1,1,1,rep(1, 5),
1,1.1,0.9,1,1,1,1.1,1,0.9,1,1,1.1,1,1,0.9,0.9,1,1.1,1,1,1,0.9,1.1,1,1,rep(1, 5),1,1,1.1,0.9,1,
1,1,1.1,1,0.9,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,1.1,1,rep(1, 5),1,1,1,1.1,0.9,0.9,1,1,1,1.1,
1,0.9,1,1,1.1,1,1,0.9,1,1.1,1,1,1,0.9,1.1,rep(1, 5)),
ncol=5, byrow=T,
dimnames=list(c("Hardy","Lonely","Adamant","Naughty","Brave","Bold","Docile","Impish","Lax","Relaxed",
"Modest","Mild","Bashful","Rash","Quiet","Calm","Gentle","Careful","Quirky","Sassy",
"Timid","Hasty","Jolly","Naive","Serious"),
c("ATK","DEF","Sp.A","Sp.D","SPD")))
b[,2:7] = (c(round((((2*base.stats[base.stats[,1]=="Articuno",2] + a[,1] + 0 + 100) * 100) / 100 + 10)),
round((((2*base.stats[base.stats[,1]=="Articuno",3] + a[,2] + 0) * 100) / 100 + 5) * nat.mat["Calm",1]),
round((((2*base.stats[base.stats[,1]=="Articuno",4] + a[,3] + 0) * 100) / 100 + 5) * nat.mat["Calm",2]),
round((((2*base.stats[base.stats[,1]=="Articuno",5] + a[,4] + 0) * 100) / 100 + 5) * nat.mat["Calm",3]),
round((((2*base.stats[base.stats[,1]=="Articuno",6] + a[,5] + 0) * 100) / 100 + 5) * nat.mat["Calm",4]),
round((((2*base.stats[base.stats[,1]=="Articuno",7] + a[,6] + 0) * 100) / 100 + 5) * nat.mat["Calm",5])))
b[,8:13] = 0
b[,14] = 100
b[,15] = "Calm"
exemplo4 = iv.calc(b[,1], b[,2:7], b[,8:13], b[,14], b[,15], interesse=25)
----
----