Tarot bot.

Bot que lee el tarot

python webdev datasci

9/10/24 10:30

hada trabajando

Este proyecto sigue en construcción.

hada trabajando

Introducción.

Abstracto

Estoy desarrollando un bot de tarot en Python que simule la experiencia de una lectura real. Utilizando ChatGPT como motor de lenguaje natural, el bot será capaz de manejar una baraja virtual, crear tiradas personalizadas, y ofrecer interpretaciones detalladas basadas en las cartas seleccionadas.

Con una interfaz tanto para Discord como para web, este proyecto busca brindar acceso a lecturas de tarot a un público amplio, incluyendo aquellos que no tienen una baraja física, quienes buscan una lectura rápida y sencilla, o aquellos que desean reducir su dependencia en lecturas constantes.

El objetivo es crear una herramienta intuitiva y confiable que preserve la esencia de una lectura de tarot tradicional, adaptada a la era digital.

Descripción de proyecto

Creación de aplicación de Python con las capacidades técnicas de un tarotista; manejo de baraja, creación de barajas para propósitos específicos, mezclado de baraja, colocación de cartas y dar su significado. Emplear un LLM para generar interpretaciones de las lecturas generadas. Darle a este dos UIs, una como bot de Discord y otra como aplicación web.

Necesidades que cubre el proyecto

  • Quienes que por algún motivo no pueden tener una baraja de tarot, pero tienen interés en su uso.
  • Quienes no tienen energía y/o capacidad para hacer sus propias lecturas.
  • Quienes tienen dependencia a las lecturas y quieren reemplazarlo.

Actividades identificadas

    Parte 1: el core

  1. Manejo de baraja/cartas
    1. Crear sistema de identificadores de las cartas
    2. Método de creación de identificadores
    3. Método de creación de barajas
  2. Mezclado de barajas
    1. Aleatorización de cartas
    2. Mezclado en abanico
    3. Aleatorizar sentido
  3. Colocación de cartas
    1. Jalar cantidades específicas de cartas
    2. Mostrar opciones de selección
    3. Opción de tomar por arriba, por abajo y por en medio
  4. Dar su significado/relaciones por carta
    1. Crear sistema de archivos
    2. Rellenar archivos
    3. Crear sistema de extracción de información de archivos
    4. Crear plantilla de texto para la información.
  5. Crear bucle de trabajo base
    1. Crear diagrama de flujo de las interacciones con el bot
    2. Guionizar interacciones con el bot
    3. Crear bucle
  6. Pruebas y documentación
    1. Crear documentación interna
    2. Crear documentación general externa
    3. Crear unittests
  7. Parte 2: simular humanidad

  8. Integrar openai en el bucle de trabajo
  9. Parte 3: Darle GUI

  10. Crear bot de Discord
  11. Crear aplicación web

Sobre el tarot

El tarot, en esencia, es un sistema de símbolos y arquetipos que se utiliza para la introspección y la orientación. Es una herramienta que ofrece perspectivas sobre diversas situaciones de la vida y ayudando a los consultantes a conectar con su intuición y, para algunos, con guías espirituales.

De acuerdo a Wikipedia, el tarot (originalmente conocido como trionfi y posteriormente como tarocchi o tarocks) es una baraja de naipes a menudo utilizada desde por lo menos mediados del siglo XV en varias partes de Europa para jugar juegos de cartas tales como el Tarocchini.

A finales del siglo XVIII, ocultistas franceses hicieron afirmaciones elaboradas, pero no corroboradas, sobre la historia y significado de las cartas, lo que llevó a la aparición de barajas personalizadas para ser usadas en la adivinación usando las cartas del tarot para obtener conocimiento o intuiciones sobre el pasado, el presente o el futuro.

Es usado desde entonces como medio de consulta e interpretación de hechos (presentes, pasados o futuros), sueños, percepciones o estados emocionales, y constituye, pues, un tipo de cartomancia.

Como se lee el tarot.

En las lecturas hay dos partes; la tirada, que puede considerarse una receta y las cartas, que vendrian a ser los ingredientes.

La tirada es un patron de colocacion de cartas, donde a cada lugar se le da un area o se le hace una pregunta.

El trabajo del tarotista es interpretar como la carta responde a la pregunta o describe el area.

Sobre las cartas

El tarot está compuesto de 78 cartas, divididas en 22 arcanos mayores y 56 menores, que a su vez se dividen en 4 palos; espadas, bastos, copas y oros/pentáculos. Cada uno con 14 cartas, numerados del 1 al 10, y después sota, caballero, reina y rey.

El arte de las cartas representa el significado de estas y cuenta una historia.

El significado cambia acorde a la dirección, teniendo un significado al estar normal y otro al estar invertida.

Cada uno de los palos tiene un area de influencia y un elemento relacionado.

De entre los arcanos menores, 36 tienen una relación con un demonio del Ars Goetia. 9 por palo, las numeradas del 2 al 10. Cada una de estas cartas tiene relación con 2 de los 72 demonios. Uno diurno y uno nocturno.

Los arcanos mayores suelen llevar la numeracion romana y algunos de ellos estan relacionados con un arquetipo jungeano.

La baraja.

Creando identificadores

Como mencioné en la introducción, las barajas del tarot se dividen en 2 grupos: la arcana mayor, que contiene 22 cartas, y la arcana menor con 56 cartas divididas en 4 palos, contando cada palo con 14 cartas.

Entonces, el tarot tiene 5 grupos de cartas. Para facilitar el manejo de las cartas, decidí darles un identificador alfanumérico único con el formato G00. G siendo el identificador del grupo y 00 el número de la carta.

Identificadores de grupos.

Grupo

Id

Min.

Max.

Arcana mayor

M

00

21

Varas / Bastos

B

01

14

Espadas

E

01

14

Copas

C

01

14

Oros /
Pentáculos

P

01

14

Al principio consideré 2 opciones para la identificación: la alfanumérica, ganadora, y un potencial identificador numérico, descartado por el pecado de dificultar el mantenimiento, la reutilización del módulo y los archivos con la información de las cartas. Esta decisión, a la larga, demostraría ser la mejor.

La parte "alfa" de alfanumérica fue fácil de definir; una letra distinta para cada grupo, listo. M de arcana mayor, E de espadas, C de copas, B de bastos (V de varas, no, siendo completamente sincera, no me gustaba cómo se veía junto con las otras) y P de pentáculos (porque, nuevamente, no me gustaba cómo se veía la O de oros). Creando la nomenclatura MECBP, pronunciado mec-bep.

La parte "numérica" de alfanumérica presenta aún menos dificultades. El uso del sistema hexadecimal fue descartado inmediatamente, pues considerando que la arcana mayor tiene 22 integrantes, no ahorraría espacio. Por practicidad, todos los identificadores debían tener exactamente la misma cantidad de caracteres; por ello, se determinó el uso de 2 posiciones numéricas.

La otra característica, la posición

Hay otra variable muy importante a considerar durante las lecturas, y esa es la posición en la que se encuentran las cartas, pudiendo ser esta recta o invertida. Recta, normal, para arriba. Invertida, al revés, para abajo.

Para facilitar la posible consulta de los datos, añadí una tercera posición, la neutra. Teniendo entonces tres posiciones Recta, Inversa y Neutra. Creando la nomenclatura RIN, pronunciada "rin".

Identificadores de posición.

Posición

Identificador

Recta

R

Inversa

I

Neutra

N

El sistema: G00P

Llamé al sistema completo G00P, pronunciado goop; G de grupo (MECBP), los dos ceros de las dos posiciones numéricas y la P de posición (RIN). Este sistema es manejable en archivos, fácil de acceder y mantener.

Todo el manejo de la baraja se realiza con la clase Deck. Esta tiene 3 y solamente 3 atributos:

deck (lista, inicialmente vacía):
Un listado de los identificadores G00P que contiene la baraja
hand (lista, inicialmente vacía):
Listado de las cartas seleccionadas para ser colocadas en el spread / tirada
suits (set ("E","C","B","P")):
Los posibles valores de los palos en G00P, omitiendo M, ya que este se maneja aparte.

Código para creación de ids por grupo.

25

def make_suit(self, suit:str, start:int, end:int):

26

"""makes the cards in a suit

27

28

Args:

29

suit (str): card suit, must be in MECBP

30

start (int): starting number of the suit

31

end (int): last number of the suit

32

"""

33

self.deck += [f"{suit}{indx:0>2}N"

34

for indx in range(start,end+1)]

Ejecutando

0

d = Deck()

1

d.make_suit("E", 1, 14)

2

print(d.deck)

...

>> ['E01N', 'E02N', 'E03N', 'E04N', 'E05N', 'E06N', 'E07N', 'E08N', 'E09N', 'E10N', 'E11N', 'E12N', 'E13N', 'E14N']

Considerando que las posiciones R o I se dan al barajear, la posición N se coloca por defecto.

Armando barajas

Muchas tiradas no requieren de la baraja completa; para obtener respuestas específicas, se puede reducir a un grupo específico de cartas.

Algunas requieren únicamente a los arcanos mayores, otras, solo un palo de los arcanos menores, porque se busca consultar la numeración. Las lecturas enfocadas a los goetia, requerirán únicamente las cartas con relación goetia.

Para reducir las barajas, yo suelo hacer las siguientes preguntas:

  1. ¿Se incluyen los arcanos mayores?

    • Sí (pasar a P2)
    • No (pasar a P3)
  2. ¿Se incluyen únicamente los arcanos mayores?

    • Sí (baraja terminada, solo arcanos mayores)
    • No (pasar a P3)
  3. ¿Se incluyen todos los palos de los arcanos menores?

    • Sí (pasar a p5)
    • No (pasar a p4)
  4. ¿Qué palos se incluyen?

      Selección múltiple, mínimo 1:

    • Espadas
    • Copas
    • Varas
    • Oros
    • Random, no importa cual.
    • Pasar a P5

  5. ¿Se incluyen todos los números?

    • Sí (baraja terminada)
    • No (pasar a P6)
  6. ¿Qué números se incluyen?

      Seleccionar 1:

    • Solo las numeradas (del 1 al 10)
    • Solo las Goetia (del 2 al 10)
    • Baraja terminada

Características de barajas
Punto Posibles

Incluir arcana mayor

Sí / no / únicamente

Palos de la arcana menor que incluyen.

Espadas / copas / varas / oros / la que sea

Números de arcana menor que incluyen.

Todos / numerados/ goetia. 

Código para construcción de baraja.

36

def build_deck( self,

37

major: bool = True,

38

all_suits: bool = True,

39

suits: list = False,

40

goetia: bool = False,

41

numbers: bool = False):

42

"""builds deck, to be called from create_deck()

43

44

Args:

45

major (bool, optional): if major arcana is included. Defaults to True.

46

all_suits (bool, optional): if all minor arcana are included. Defaults to True.

47

suits (list, optional): wich minor arcana suits are included. Defaults to False.

48

goetia (bool, optional): if only goetia related cards are included. Defaults to False.

49

numbers (bool, optional): if only numbered cards are included. Defaults to False.

50

"""

51

self.refresh()

52

if suits:

53

suits = [i for i in

54

[x.upper() for x in suits]

55

if i in self.suits]

56

elif all_suits:

57

suits = self.suits

58

59

if major:

60

self.make_suit( "M", 0, 21)

61

62

if suits:

63

if goetia:

64

start,end = 2, 10

65

elif numbers:

66

start,end = 1, 10

67

else:

68

start,end = 1, 14

69

70

for i in suits:

71

self.make_suit( i, start, end)

Ejecutando

0

d = Deck()

1

d.build_deck(major = False, suits = ["E"], goetia = True)

2

print(d.deck)

3

...

>> ['E02N', 'E03N', 'E04N', 'E05N', 'E06N', 'E07N', 'E08N', 'E09N', 'E10N']

Creando la baraja (en base a un comando de texto)

Considerando estos puntos, definí reglas de creación de baraja, que funcionan como variables de comando. Siendo estas:

onlymajor:
Únicamente arcana mayor
nomajor:
La arcana mayor no se incluye
suite:
Se incluye el palo de espadas
suitc:
Se incluye el palo de copas
suitb:
Se incluye el palo de varas
suitp:
Se incluye el palo de oros
suitr:
Se incluye un palo aleatorio, estos pueden acumularse, siendo el máximo reconocido 3. Superando estos, simplemente se añaden todos los palos a la lista de reglas.
numbered:
De la arcana menor, solo las cartas numeradas (del 1 al 10)
goetia:
De la arcana menor, solo las cartas con relación goetia (del 2 al 10)

Código para creación baraja.

72

def create_deck(self, rules: str = ""):

73

"""creates a deck based on given rules

74

75

Args:

76

rules (str, optional): rules to follow. Defaults to "" (no rules).

77

78

Raises:

79

ValueError: in case deck is empty

80

"""

81

if "onlymajor" in rules:

82

self.build_deck(all_suits = False)

83

return

84

85

if "suitr" in rules:

86

tot = rules.count("suitr")

87

if tot > 3:

88

rules += " ".join([f"suit{y.lower()}" for y in self.suits])

89

else:

90

poss = self.suits

91

shuffle(poss)

92

rules += " ".join([f"suit{y.lower()}" for y in poss[:tot]])

93

94

suits = [x[-1] for x in

95

[f"suit{y.lower()}" for y in self.suits]

96

if x in rules]

97

98

self.build_deck("nomajor" not in rules,

99

len(suits) == 0, suits,

100

"goetia" in rules,

101

"numbered" in rules)

102

103

if len(self.deck) == 0:

104

raise ValueError(f"cant work with an empty deck check rules {rules}")

Ejecutando

0

d = Deck()

1

d.create_deck("nomajor suite goetia")

2

print(d.deck)

3

...

>> ['E02N', 'E03N', 'E04N', 'E05N', 'E06N', 'E07N', 'E08N', 'E09N', 'E10N']

Barajear la baraja (digital)

Ya con la baraja hecha, el primer cambio que se le hace es barajearla. Este proceso les da una posición (RI) y al aleatorizarlas se da ingreso a la suerte y se puede realizar la lectura.

Al no tener las cartas físicas, el mezclado y la asignación de posición se realizan por separado. Veamos primero la posición.

Trabajando el RI: generando posición

Para la generación de posición se usa una "lucky string" o cadena de la suerte. Esta, a diferencia de la de Carmen, no se pierde. Se genera una string con una cantidad aleatoria de R e Is, entre 5 y 15 + una pequeña varianza dada por los "tips" que se obtienen del usuario.

Esta cadena de Rs e Is se convierte en lista y se aleatoriza. Con esto, carta por carta, se elige un punto igual aleatorio de la cadena.

RIN: Generar posición.

106

def generate_position( self, tips:list):

107

"""generates card position

108

109

Args:

110

tips (list, optional): numbers that modify luck for positions. Defaults to [1,3].

111

"""

112

luck_string = list("R" * (randint(5,15) + choice(tips)) +

113

"I" * (randint(1,12) + choice(tips)))

114

shuffle(luck_string)

115

self.deck = [f"{x[:-1]}{choice(luck_string)}" for x in self.deck]

Ejecutando

0

d = Deck()

1

d.create_deck("nomajor suite goetia")

2

d.generate_position( [3,5] )

3

print(d.deck)

4

5

>> ['E02R', 'E03I', 'E04R', 'E05I', 'E06R', 'E07R', 'E08R', 'E09R', 'E10R']

¿Qué tanto puede variar la cantidad de cartas rectas e invertidas en una baraja usando este algoritmo? Para refinar los datos de creación de baraja, genere las posiciones de una baraja completa 250 mil veces y recopile las proporciones de R e I. En la siguiente tabla puede verse la cantidad de cartas invertidas presentes en esta muestra.

Datos del muestreo de 250,000 barajeadas

Is presentes en %

Is presentes

Ocurrencias

01.39%

1

0007

02.78%

2

0017

04.17%

3

0070

05.56%

4

0166

06.94%

5

0325

08.33%

6

0567

09.72%

7

0819

11.11%

8

1133

12.50%

9

1489

13.89%

10

1782

15.28%

11

2133

16.67%

12

2334

18.06%

13

2815

19.44%

14

3003

20.83%

15

3428

22.22%

16

3823

23.61%

17

4297

25.00%

18

4473

26.39%

19

4750

27.78%

20

5219

29.17%

21

5569

30.56%

22

5967

31.94%

23

6105

33.33%

24

6474

34.72%

25

6827

36.11%

26

7001

37.50%

27

7435

38.89%

28

7770

40.28%

29

7984

41.67%

30

8053

43.06%

31

8439

44.44%

32

8540

45.83%

33

8623

47.22%

34

8740

48.61%

35

8395

50.00%

36

8485

51.39%

37

8442

52.78%

38

8025

54.17%

39

7539

55.56%

40

7155

56.94%

41

6825

58.33%

42

6319

59.72%

43

5732

61.11%

44

5455

62.50%

45

4845

63.89%

46

4353

65.28%

47

3814

66.67%

48

3485

68.06%

49

2986

69.45%

50

2573

70.83%

51

2139

72.22%

52

1782

73.61%

53

1435

75.00%

54

1110

76.39%

55

0872

77.78%

56

0611

79.17%

57

0498

80.56%

58

0359

81.95%

59

0242

83.33%

60

0151

84.72%

61

0091

86.11%

62

0047

87.50%

63

0021

88.89%

64

0020

90.28%

65

0010

91.67%

66

0005

93.06%

67

0002

Muestreo-de-RI

Grafico de frecuencia de I

Barajeado por la maquina

Para el barajeado de naturaleza completamente digital, computacional y difícilmente replicable por el humano, decidí usar el método shuffle del módulo random (te amamos random). Si bien muchas teclas se han desgastado discutiendo si la aleatorización computacional es válida o fiable, porque, realmente, no es aleatoria, sino que es generada, el barajeado humano tampoco es tan aleatorio. 

Para esta aplicación, los generadores de números pseudoaleatorios (PRNGs) que podemos considerar el "barajeado" de la máquina; a pesar de ser influenciado por los nanosegundos, la entropia y los fotones, es perfecto.

Mezclado completamente aleatorio

117

def hard_mix(self):

118

"""shuffles deck

119

"""

120

shuffle(self.deck)

Ejecutando

0

d = Deck()

1

d.create_deck("nomajor goetia suite")

2

d.hard_mix()

3

print(d.deck)

4

...

>> ['E03N', 'E04N', 'E10N', 'E02N', 'E05N', 'E08N', 'E09N', 'E07N', 'E06N']

Barajeando como humano (casi)

Los humanos barajean por lo general de dos maneras; en abanico y en bloque o corte. Llamé "abanico" el dividir la baraja en dos o más partes y mezclarlas, si bien hay muchísimas técnicas para hacer esto físicamente, solo buscamos emularlo lo más cercano posible. La otra forma es cortar o de bloque. En este, se divide la baraja en varias partes y se cambia la posición en la que estaban, sin mezclar los bloques entre sí.

Estas dos comparten una característica: se tiene que dividir la baraja en varias (mínimo 2) partes. Para esa labor, cree un método estático.  Y otro para verificar que la cantidad de partes que se busca cortar sea viable, es decir, si me pidieras cortar una baraja que tiene solo la arcana mayor (de 22 cartas) en 25 partes, sería imposible. Si me pides que la parta en 22 incluso, sería algo más cercano al hard_mix, se perdería por completo la "energía" o entropía que lleva la baraja.

Partir baraja (estatico)

122

@staticmethod

123

def cutted(bunch:list, parts: int = 5):

124

"""cuts a list in given parts

125

126

Args:

127

bunch (list): list to be cutted

128

parts (int, optional): parts to be cutted in. Defaults to 5.

129

130

Returns:

131

list: nested list with parts

132

"""

133

if len(bunch) % parts != 0:

134

bunch += list( " " * (parts - (len(bunch) % parts)))

135

bites = len(bunch) // parts

136

return [bunch[(bites * step):(bites * (step + 1))]

137

for step in range(parts)]

138

El mínimo de partes es 2, se necesitan mínimo dos partes para que se pueda hablar de partes en plural, pero ¿por qué la cantidad máxima de partes es una cuarta parte de la cantidad de cartas en la baraja? Bueno, por una pequeña limitación que me encontré durante una de las primeras pruebas de la clase ya integrada.  Un problema proveniente de mi propia ambición: la creación de barajas goetia.

Si bien en la práctica cualquier lectura que se limite a las cartas goetia incluye todos los palos, por cómo funciona la creación de las barajas, es perfectamente viable pedir una baraja que tenga solo un palo y solo las cartas goetia. Por ello, que la baraja más pequeña posible es una de 8 cartas.

Inicialmente, el número máximo de partes era una quinta parte de la cantidad de cartas. En mi consideración, este número era ideal. La baraja más pequeña de uso común es la numerada de un palo, con 10 integrantes, 10 entre 5 da 2, dos integrantes mínimos por parte. Por supuesto, esto pasa a ser imposible en la baraja más pequeña creable, 8 entre cinco da 1.6 y al momento de crear el rango de posibilidades, el número máximo resulta menor que el mínimo.

Podríamos, por supuesto, hacer imposible la creación de una baraja así en la GUI, pero si alguien modificara los archivos para que pidan una baraja así, el crearla resultaría en un error fatal. El peor tipo de errores.

Verificar si la cantidad de partes es segura

139

def parts_check( self, parts : int):

140

"""checks if given parts is a valid number

141

142

Args:

143

parts (int): parts we want to cut deck into

144

145

Returns:

146

int: actual parts it will be cut into

147

"""

148

if parts >= len(self.deck) // 4 or parts < 2:

149

return randint(2, len(self.deck) // 4)

150

return parts

Abanico

Técnicamente, ocurren 4 mezclados en esta función. Primero, el orden de las partes se revuelve. Segundo, cada una de las partes se revuelve entre sí. Tercero, las partes se unen en abanico, mezclándose entre ellas y creando nuevas partes y, por cuarto y último, las nuevas partes también se revuelve.

Después de mucha prueba y mucho error, quedé con esta función que permite la existencia de "pegados" (cuando dos cartas son consecutivas) esporádicos. Y se asegura de que la cantidad máxima de "pegados" sea 2. El resultado de esto es una mezcla de tarjetas que se siente natural y se mantiene aleatoria. 

Mezclado de abanico.

152

def fan_mix( self, parts:int = 5):

153

"""mix deck in fan

154

155

Args:

156

parts (int, optional): parts deck will be cutted into. Defaults to 5.

157

"""

158

c = self.cutted( self.deck,

159

self.parts_check( parts ))

160

[shuffle(i) for i in c]

161

c = [[x[y] for x in c] for y in range(len(c[0]))]

162

[shuffle(i) for i in c]

163

164

self.deck= [item for box in c

165

for item in box if item != " "]

Ejecutando

0

d = Deck()

1

d.create_deck("nomajor suite")

2

d.fan_mix(3)

3

print(d.deck)

4

5

>> ['E12N', 'E02N', 'E08N', 'E10N', 'E01N', 'E13N', 'E03N', 'E09N', 'E06N', 'E05N', 'E14N', 'E04N', 'E11N', 'E07N']

tarot-bot-visual-fanmix

Hilary Duff disfrutando su flip-phone en la película La Nueva Cenicienta.

Mezclado por bloques.

167

def block_mix(self, parts:int = 5):

168

"""cuts deck in blocks and mixes them

169

170

Args:

171

parts (int, optional): parts deck will be cutted into. Defaults to 5.

172

"""

173

c = self.cutted( self.deck,

174

self.parts_check( parts ))

175

shuffle(c)

176

self.deck= [item for box in c

177

for item in box if item != " "]

Ejecutando

0

d = Deck()

1

d.create_deck("nomajor goetia suite")

2

d.block_mix(3)

3

print(d.deck)

4

5

>> ['E08N', 'E09N', 'E10N', 'E05N', 'E06N', 'E07N', 'E02N', 'E03N', 'E04N']

Jalar a mano.

179

def pull_to_hand(self, num:int, pull_from:str = "t"):

180

"""pull a certain amount of cards from top of deck to hand

181

182

Args:

183

num (int): num of cards to pull

184

"""

185

if num > len(self.deck):

186

raise ValueError(f"Cant pull {num} from deck, theres only {len(self.deck)} cards")

187

if pull_from[0].lower() == "b":

188

self.hand += [self.deck.pop(-1) for x in range(num)]

189

elif pull_from[0].lower() == "m":

190

self.hand += [ self.deck.pop (len(self.deck) // 2) for x in range(num) ]

191

else:

192

self.hand += [self.deck.pop(0) for x in range(num)]

Las cartas

Creando una guía de las cartas del Tarot

Al momento de redactar esta parte, te puedo decir, con profundo pesar y completa certeza, que esta fue la parte más agobiante, repetitiva y poco interesante de todo el proyecto.

En parte, me temo, porque en esto no recibí muchísimos conocimientos novedosos y cuando lo hice, tuve que usar cada milinewton de mi fuerza de voluntad para no caer en un agujero de conejo, que si bien me haría más sabia, podría descarrilar el proyecto por completo.

Más abajo puedes navegar cómodamente la información reunida sobre las cartas y los demonios del Ars Goetia.

Pero esa es la versión para consulta de humanos, la tercera versión para consulta humana, generada a partir de la versión para consulta del programa, que, a su vez, se derivó de la segunda versión para consulta humana, la cual es... complicada de navegar.

La versión para consulta desde el código es un conjunto de archivos json, con diferencias para la arcana mayor y la menor y un archivo extra por cada uno de los palos.

A continuación te muestro ejemplos de los 3 tipos de archivos para las cartas; E01 (menor sin goetia), E02 (menor con goetia) y M00 (mayor).

Json de E01.

0

{

1

"id": "E01",

2

"name_card": "As de Espadas",

3

"card_power": "Es un indicador de nuevos comienzos, oportunidades y potencial.",

4

"normal": [

5

"Conquista", "Triunfo logrado a pesar de los problemas", "Actividad intensa", "Gestación o parto"

6

],

7

"invert": [

8

"Desastre o conquista seguida por un desastre", "Gran pérdida", "Muerte violenta", "Infertilidad"

9

]

10

}

Json de E02.

0

{

1

"id": "E02",

2

"name_card": "Dos de Espadas",

3

"card_power": "Simboliza dualidad, equilibrio y colaboración.",

4

"normal": [

5

"Paz", "Fuerzas balanceadas", "Fortaleza", "Amistad."

6

],

7

"invert": [

8

"Deslealtad", "Cambios, a veces en la dirección equivocada", "Peleas"

9

],

10

"days": {

11

"start":"09/23",

12

"end": "10/02"

13

},

14

"d_goetia": {

15

"name":"Sallos",

16

"number": 19,

17

"title": "Duque",

18

"planet": "Venus",

19

"metal": "Cobre",

20

"complete_title": "Es un gran y poderoso duque",

21

"descrip": "Aparece en la forma de un valiente soldado montado en un cocodrilo, con una corona ducal en la cabeza. Es muy pacífico.",

22

"skills": "Causa amor",

23

"legions": "30 legiones de espíritus."

24

},

25

"n_goetia": {

26

"name":"Orbas",

27

"number": 55,

28

"title": "Príncipe",

29

"planet": "Jupiter",

30

"metal": "Estaño",

31

"complete_title": "Es un príncipe grande y poderoso",

32

"descrip": "Al principio parece un caballo; pero después de la orden del exorcista adopta la imagen de un hombre.",

33

"skills": "Su oficio es descubrir todas las cosas. pasado, presente y por venir; también para dar Dignidades, y Prelaturas, y el favor de amigos y de enemigos. Da verdaderas respuestas de la divinidad, y de la creación del mundo. Es muy fiel al Exorcista, y a la voluntad. No permitas que sea tentado por ningún Espíritu.",

34

"legions": "20 Legiones de Espíritus."

35

}

36

}

Json de M00.

0

{

1

"id": "M00",

2

"roman_num": "O",

3

"name_card": "El Loco",

4

"card_power": "Simboliza el inicio de un ciclo nuevo, la confianza en el proceso y la valentía con la que te embarcas en un viaje desconocido.",

5

"descrip": "El feliz viajero que ve el mundo a través de los ojos de un niño",

6

"jung": "El inocente",

7

"powers": [

8

"Libertad", "Búsqueda de nuevas experiencias", "Espontaneidad"

9

],

10

"normal":[

11

"Representa inocencia", "Señala el comienzo auspicioso de nuevas aventuras y oportunidades", "También simboliza la voluntad entusiasta de hacer el ridículo y alcanzar el propio ser superior."

12

],

13

"invert":[

14

"Indica que se han tomado o son inminentes las decisiones equivocadas."

15

]

16

}

Datos recopilados sobre las cartas

Los datos contenidos en este libro de calculo son derivados de los archivos json creados para el bot.

Puedes acceder al documento con mas comodidad y comentarlo aquí.

Cierre