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" )
0 commit comments