def vector_length(v): squares_sum = 0 for a in v: squares_sum += a**2 return squares_sum ** 0.5
La difficoltà centrale dell'esercizio è trovare un modo per ricavare la posizione di un carattere nell'alfabeto: mentre di solito si conosce l'indice e si vuole il dato, qua serve il contrario.
Un modo è modificare la funzione presente
nelle slide in modo che invece di dare una informaziona booleana (presente/non presente)
dia la posizione effettiva.
def find_index(elem, a): # tradizionalmente l'elemento da cercare si dice needle (ago) e la lista haystack (pila di paglia) i = 0 while i < len(a): if a[i] == elem: return i i += 1 return -1
È comune usare -1 come risultato nel caso non si trovi l'elemento (poiché non è un indice valido) ma si potrebbe usare allo stesso scopo
anche None
o qualsiasi altro valore che non si confonda con un indice (oppure si potrebbe usare un'eccezione, argomento non trattato).
Una prima soluzione può essere questa:
def find_index(elem, a): i = 0 while i < len(a): if a[i] == elem: return i i += 1 return -1 def decodifica(messaggio, alfabeto): messaggio_decodificato = '' for carattere in messaggio: i = find_index(carattere, alfabeto) if i == 0: messaggio_decodificato += 'a' if i == 1: messaggio_decodificato += 'b' if i == 2: messaggio_decodificato += 'c' if i == 3: messaggio_decodificato += 'd' if i == 4: messaggio_decodificato += 'e' if i == 5: messaggio_decodificato += 'f' if i == 6: messaggio_decodificato += 'g' if i == 7: messaggio_decodificato += 'h' if i == 8: messaggio_decodificato += 'i' if i == 9: messaggio_decodificato += 'j' if i == 10: messaggio_decodificato += 'k' if i == 11: messaggio_decodificato += 'l' if i == 12: messaggio_decodificato += 'm' if i == 13: messaggio_decodificato += 'n' if i == 14: messaggio_decodificato += 'o' if i == 15: messaggio_decodificato += 'p' if i == 16: messaggio_decodificato += 'q' if i == 17: messaggio_decodificato += 'r' if i == 18: messaggio_decodificato += 's' if i == 19: messaggio_decodificato += 't' if i == 20: messaggio_decodificato += 'u' if i == 21: messaggio_decodificato += 'v' if i == 22: messaggio_decodificato += 'w' if i == 23: messaggio_decodificato += 'x' if i == 24: messaggio_decodificato += 'y' if i == 25: messaggio_decodificato += 'z' return messaggio_decodificato f = open('segreto.txt') testo_criptato = f.read() f.close() alfabeto_casuale = ['m', 'r', 'o', 'e', 'i', 'b', 'z', 'j', 't', 'g', 'c', 'f', 'p', 'h', 'x', 'd', 'k', 'v', 'l', 's', 'y', 'n', 'w', 'q', 'u', 'a'] print(decodifica(testo_criptato.strip(), alfabeto_casuale))
La soluzione è intuitiva ma molto lunga. Ispirandosi al codice usato per generare l'alfabeto casuale, si possono usare le funzioni builtin ord
e chr
che convertono da carattere a rispettiva codifica ASCII (che è un numero). La 'a' minuscola ha codice ASCII 97, come si può verificare usando ord("a") o chr(97).
def decodifica(messaggio, alfabeto): messaggio_decodificato = '' for carattere in messaggio: i = find_index(carattere, alfabeto) messaggio_decodificato += chr(ord('a') + i) return messaggio_decodificato
Infine, conoscendo i metodi, si poteva fare a meno della funzione find_index perché le liste hanno un metodo che fa esattamente quello:
# prima: i = find_index(carattere, alfabeto) i = alfabeto.index(carattere)
def distance(v1, v2): return vector_length(vector_difference(v1, v2))