Skip to content

Commit 60b3a6f

Browse files
committed
Automata v.1.4.1
Fixed error: when automata empties the stack, and there is more transitions to do, it know update the automata state to [error], to avoid the poping of null values of the stack. It also has a two new implementations: safebox automatas simulator for example :3
1 parent 50958b6 commit 60b3a6f

File tree

3 files changed

+294
-3
lines changed

3 files changed

+294
-3
lines changed

pda.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ def transite(self, symbol: str, printStep: bool = False):
179179
for transition in self.Transitions:
180180
# print(self.stack[len(self.stack)-1])
181181
# print(f"if ({current} == {transition[0]}) and ({symbol} == {transition[1]} or {transition[1]} == \"\") and ({self.stack[len(self.stack)-1]} == {transition[2]}):")
182-
if (current == transition[0]) and (symbol == transition[1] or transition[1] == "") and (self.stack[len(self.stack)-1] == transition[2]):
182+
if (current == transition[0]) and (symbol == transition[1] or transition[1] == "") and (self.stack[len(self.stack)-1] == transition[2]) and (not self.error):
183183
print(" * Transición a tomar:", transition)
184184
validTransitions.append(transition)
185185

186186
# If Automata has 0 transitions, it will go to the "limbo"; means error;
187187
# But only if it is more string to read:
188188
takesALambdaTransition = False
189-
if len(validTransitions) == 0:
189+
if len(validTransitions) == 0 and len(self.stack) > 0:
190190
# If there is no more string:
191191
if symbol == "":
192192
# Checks if it arrives to a final state:
@@ -227,7 +227,11 @@ def transite(self, symbol: str, printStep: bool = False):
227227
newStates.append(transition[4])
228228

229229
# It pop the stack top symbol:
230-
self.stack.pop()
230+
if len(self.stack) > 0:
231+
self.stack.pop()
232+
else:
233+
self.error = True
234+
return
231235

232236
# It push down symbols on the stack:
233237
stacking = transition[3]

safebox-generator.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
from dfa import DFA
2+
import os
3+
4+
def generateDFA(password: str):
5+
6+
#? DFA:
7+
#* Se espera que el autómata acepte:
8+
#* { wxv: w, v en {L, R}*, x es la contraseña };
9+
Automata = DFA()
10+
Automata.setAlphabet({"L", "R"})
11+
12+
#* Se comienza con el dibujo del autómata:
13+
# print(f"\nAutómata generado para \"{password}\":\n")
14+
15+
16+
#? ESTRUCTURA INICIAL ?#
17+
'''
18+
Se espera que el autómata acepte la contraseña de
19+
la caja fuerte independientemente de lo que venga
20+
antes de esta (v en {L, R}*); por ente, es necesario
21+
crear una estructura particular para el primer grupo
22+
de caracteres de la contraseña:
23+
24+
* Si la contraseña comienza con movimientos a la
25+
izquierda "L"; se "registra" este hecho.
26+
27+
* Si la contraseña comienza con movimientos a la
28+
derecha "R"; se "registra" este hecho.
29+
30+
Se toma este primer símbolo como la transición que
31+
el estado inicial tiene para avanzar a estados
32+
siguientes, y el complemento del símbolo (el otro),
33+
para generar un ciclo en el que no sale del estado
34+
inicial. Es decir, cuando se esté leyendo el inicio
35+
de la cadena, se espera que cuando lea el símbolo
36+
con el que inicia la contraseña, comience a avanzar
37+
suponiendo que ya se está tecleando la contraseña,
38+
en caso de que se lean otros símbolos, seguirá a la
39+
espera de que este primer símbolo llegue.
40+
41+
Esta primer estructura tiene "x" estados; en donde
42+
"x" representa la cantidad de movimientos del primer
43+
dígito de la contraseña (cantidad de símbolos de la
44+
estructura inicial, antes de comenzar con otra letra).
45+
46+
Los "x" estados de esta estructura regresan al estado
47+
inicial cuando encuentran un símbolo que no es igual al
48+
inicial de la contraseña, y avanzan hasta que el último
49+
estado de esta estructura (el número "x"), debe comenzar
50+
a leer otras letras, en ese caso, se ciclará a sí mismo
51+
mientras siga leyendo el símbolo inicial; esto porque se
52+
espera que si antes de la contraseña vinieron "mil" veces
53+
ese símbolo, los registre todos de manera igualmente válida
54+
que si sólo vinieron "x".
55+
'''
56+
#? Estado incial:
57+
Automata.setInitial("q0")
58+
#? Símbolo inicial:
59+
initialSymbol = password[0]
60+
#? Primeras transiciones:
61+
if initialSymbol == "L":
62+
Automata.addTransition(("q0", "R", "q0"))
63+
# print(f"(\'q0\', \'R\', \'q0\')")
64+
Automata.addTransition(("q0", "L", "q1"))
65+
# print(f"(\'q0\', \'L\', \'q1\')")
66+
notInitialSymbol = "R"
67+
else:
68+
Automata.addTransition(("q0", "L", "q0"))
69+
# print(f"(\'q0\', \'L\', \'q0\')")
70+
Automata.addTransition(("q0", "R", "q1"))
71+
# print(f"(\'q0\', \'R\', \'q1\')")
72+
notInitialSymbol = "L"
73+
74+
#? Primeros "x" estados:
75+
index = 1
76+
77+
#? Le las "x" repeticiones del primer símbolo;
78+
#? y crea estados para cada uno; bajo las reglas
79+
#? de la primer estructura:
80+
while initialSymbol == password[index]:
81+
82+
#/ Nuevo estado x:
83+
Automata.addState(str(f"q{index}"))
84+
85+
#/ Transición de este estado hacia le siguiente;
86+
#/ Avanzando porque encontró el símbolo inicial:
87+
Automata.addTransition((str(f"q{index}"), initialSymbol, str(f"q{index+1}")))
88+
# print(f"(\'q{index}\', \'{initialSymbol}\', \'q{index+1}\')")
89+
90+
#/ Transición en el que regresa al estado inicial:
91+
#/ Esto porque encontró un símbolo diferente al inicial:
92+
Automata.addTransition((str(f"q{index}"), notInitialSymbol, "q0"))
93+
# print(f"(\'q{index}\', \'{notInitialSymbol}\', \'q0\')")
94+
95+
index += 1
96+
97+
#? Crea el ciclo descrito para el último estado "x":
98+
#/ Transición para sí mismo:
99+
Automata.addState(str(f"q{index+1}"))
100+
Automata.addTransition((str(f"q{index}"), initialSymbol, str(f"q{index}")))
101+
# print(f"(\'q{index}\', \'{initialSymbol}\', \'q{index}\')")
102+
103+
#/ Transición para avanzar con el siguiente tipo de símbolo:
104+
Automata.addTransition((str(f"q{index}"), notInitialSymbol, str(f"q{index+1}")))
105+
# print(f"(\'q{index}\', \'{notInitialSymbol}\', \'q{index+1}\')")
106+
107+
108+
#? ESTRUCTURA GENERAL:
109+
'''
110+
Esta estructura sirve para el resto de dígitos de la contraseña;
111+
Para cada símbolo siguiente seguirá las reglas:
112+
113+
* Se crea un estado para cada siguiente movimiento (caracter):
114+
- Crea una transición para avanzar al siguiente estado,
115+
según el símbolo actual de la contraseña.
116+
- Cuando estás leyendo el símbolo inicial; la otra transición
117+
va a "q0"; es decir, vuelve a empezar porque al estar leyendo
118+
algo en la contraseña fue incorrecto.
119+
- Cuando estás leyendo el símbolo no-inicial, la otra transición
120+
va a "q1", porque supone que te equivocaste, pero que este error
121+
podría significar que es el primer símbolo correcto de la contraseña.
122+
'''
123+
print()
124+
#* Si toca cambiar de dirección al siguiente movimiento;
125+
#* Esto porque el siguiente caracter es diferente al actual:
126+
if index != len(password)-1 and password[index] != password[index+1]:
127+
change = True
128+
else:
129+
change = False
130+
index += 1
131+
132+
while index < len(password):
133+
134+
#* Se crea el estado para el símbolo actual:
135+
Automata.addState(str(f"q{index}"))
136+
137+
#* Se crea una transición de avance:
138+
Automata.addTransition((str(f"q{index}"), password[index], str(f"q{index+1}")))
139+
# print((str(f"q{index}"), password[index], str(f"q{index+1}")))
140+
141+
#? Si se está leyendo el caracter inicial:
142+
if password[index-1] == initialSymbol:
143+
#/ Transición de retroceso:
144+
if not change:
145+
Automata.addTransition((str(f"q{index}"), notInitialSymbol, "q0"))
146+
# print((str(f"q{index}"), notInitialSymbol, "q0"))
147+
else:
148+
Automata.addTransition((str(f"q{index}"), initialSymbol, "q1"))
149+
# print((str(f"q{index}"), initialSymbol, "q1"))
150+
151+
#? Si se está leyendo el caracter no-inicial:
152+
else:
153+
#/ Transición de retroceso:
154+
if not change:
155+
Automata.addTransition((str(f"q{index}"), initialSymbol, "q1"))
156+
# print((str(f"q{index}"), initialSymbol, "q1"))
157+
else:
158+
Automata.addTransition((str(f"q{index}"), notInitialSymbol, "q0"))
159+
# print((str(f"q{index}"), notInitialSymbol, "q0"))
160+
161+
#* Si toca cambiar de dirección al siguiente movimiento;
162+
#* Esto porque el siguiente caracter es diferente al actual:
163+
if index != len(password)-1 and password[index] != password[index+1]:
164+
change = True
165+
else:
166+
change = False
167+
index += 1
168+
169+
print()
170+
#? ESTRUCTURA FINAL:
171+
'''
172+
Esta estructura consiste en el estado final, al que se llegó
173+
SÓLO si la contraseña fue correcta; en ese caso, se ciclará
174+
a sí mismo independientemente de lo que reciba después; ya
175+
que la caja ya está abierta.
176+
'''
177+
Automata.addState(str(f"q{index}"))
178+
Automata.addTransition((str(f"q{index}"), "L", str(f"q{index}")))
179+
# print(f"(\'q{index}\', \'L\', \'q{index}\')")
180+
Automata.addTransition((str(f"q{index}"), "R", str(f"q{index}")))
181+
# print(f"(\'q{index}\', \'R\', \'q{index}\')")
182+
Automata.setFinals({str(f"q{index}")})
183+
184+
185+
#/ Executes the Automata:
186+
'''
187+
while True:
188+
word = input("Cadena: ")
189+
if Automata.accepts(word, stepByStep=False):
190+
# print(f"La cadena \"{word}\" SÍ es aceptada!")
191+
else:
192+
# print(f"La cadena \"{word}\" NO es aceptada!")
193+
'''
194+
195+
Automata.show()
196+
return Automata
197+
198+
199+
#? Punto de ejecución:
200+
if __name__ == "__main__":
201+
202+
while True:
203+
print("\n")
204+
os.system("cls")
205+
password = input("Contraseña: ")
206+
generateDFA(password)
207+
print("\n")
208+
os.system("pause")

safebox-validator.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from pda import PDA
2+
import os
3+
4+
def validatePassword(password: str):
5+
6+
'''
7+
Recibe una contraseña y valida si es
8+
correcta para el contexto de la caja
9+
fuerte, utilizando una autómata de
10+
pila que valida el siguiente formato:
11+
12+
L = { (L^n)(R^m)(L^o)(R^p):
13+
(4 <= n + m + o + p <= 40) };
14+
15+
Es decir; contraseñas con grupos de
16+
L's, luego R's, luego L's, luego R's,
17+
en donde cada grupo tenga por lo menos
18+
un caracter, y en conjunto no sumen más
19+
de 4 caracteres como longitud.
20+
21+
Esta propuesta no está implementada en
22+
la aplicación, por lo que es agena a esta,
23+
se propone como propuesta interesante
24+
tener constraseñas con el lenguaje:
25+
L' = { L = { (L^n)(R^m)(L^o)(R^p):
26+
(1 <= n, m, o, p <= 10 };
27+
28+
Es decir; contraseñas de cuatro grupos
29+
alternados (iguales a la propuesta anterior,
30+
pero en los cuales cada uno sólo admite un
31+
máximo de 10 símbolos).
32+
33+
También se propone a futuro extender el
34+
lenguaje que acepte contraseñas que comienzen
35+
con grupos de R's, no de sólo L's.
36+
37+
Retorna verdadero o falso según acepte o no
38+
acepte la contraseña de parámetro.
39+
'''
40+
41+
#? Se crea instancia del autómata (de pila):
42+
Estados = {"q0", "q1", "q2", "q3", "q4", "q5"}
43+
Alfabeto = {"L", "R"}
44+
Inicial = "q0"
45+
Finales = {"q4"}
46+
Alfapila = {"1", "Z"}
47+
Pila = ["Z"]
48+
Transiciones = [
49+
("q0", "L", "Z", "1111111111111111111111111111111111111111Z", "q1"),
50+
("q1", "L", "1", "", "q1"),
51+
("q1", "R", "1", "", "q2"),
52+
("q2", "R", "1", "", "q2"),
53+
("q2", "L", "1", "", "q3"),
54+
("q3", "L", "1", "", "q3"),
55+
("q3", "L", "1", "", "q3"),
56+
("q3", "R", "1", "", "q4"),
57+
("q4", "R", "1", "", "q4"),
58+
("q4", "", "Z", "Z", "q5")
59+
]
60+
Automata = PDA(Estados, Alfabeto, Transiciones, Inicial, Finales, Alfapila, Pila)
61+
Automata.show()
62+
print()
63+
return True if Automata.accepts(password, stepByStep=False) else False
64+
65+
66+
#* Punto de ejecución:
67+
if __name__ == "__main__":
68+
while True:
69+
os.system("cls")
70+
print()
71+
password = input("Contraseña: ")
72+
if validatePassword(password):
73+
print(f"\nLa contraseña \"{password}\" SÍ es válida")
74+
else:
75+
print(f"\nLa contraseña \"{password}\" NO es válida")
76+
print()
77+
print("═"*40)
78+
print("\n")
79+
os.system("pause")

0 commit comments

Comments
 (0)