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
- Manejo de baraja/cartas
- Crear sistema de identificadores de las cartas
- Método de creación de identificadores
- Método de creación de barajas
- Mezclado de barajas
- Aleatorización de cartas
- Mezclado en abanico
- Aleatorizar sentido
- Colocación de cartas
- Jalar cantidades específicas de cartas
- Mostrar opciones de selección
- Opción de tomar por arriba, por abajo y por en medio
- Dar su significado/relaciones por carta
- Crear sistema de archivos
- Rellenar archivos
- Crear sistema de extracción de información de archivos
- Crear plantilla de texto para la información.
- Crear bucle de trabajo base
- Crear diagrama de flujo de las interacciones con el bot
- Guionizar interacciones con el bot
- Crear bucle
- Pruebas y documentación
- Crear documentación interna
- Crear documentación general externa
- Crear unittests
Parte 2: simular humanidad
- Integrar openai en el bucle de trabajo
Parte 3: Darle GUI
- Crear bot de Discord
- 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.
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:
¿Se incluyen los arcanos mayores?
- Sí (pasar a P2)
- No (pasar a P3)
¿Se incluyen únicamente los arcanos mayores?
- Sí (baraja terminada, solo arcanos mayores)
- No (pasar a P3)
¿Se incluyen todos los palos de los arcanos menores?
- Sí (pasar a p5)
- No (pasar a p4)
¿Qué palos se incluyen?
Selección múltiple, mínimo 1:
- Espadas
- Copas
- Varas
- Oros
- Random, no importa cual.
Pasar a P5
¿Se incluyen todos los números?
- Sí (baraja terminada)
- No (pasar a P6)
¿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 |
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']
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)]
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í.