Come se questa sfida potesse essere più nello spirito di Pythonesque ... Non è richiesta alcuna conoscenza preliminare delle catene di Markov o delle tecniche di crittografia.
Sei una spia che ha bisogno di ottenere alcune informazioni cruciali dal servizio di sicurezza britannico M1S. Gli agenti di M1S sono ben consapevoli che i loro segnali Wi-Fi possono essere intercettati, le loro vulnerabilità di sicurezza Android / iOS sfruttate ecc., Quindi tutti usano Nokia 3310 per trasmettere informazioni di testo che vengono digitate utilizzando il completamento automatico T9 .
In precedenza avevi hackerato i telefoni per essere consegnati all'agenzia di intelligence e avevi installato keylogger sotto le loro gloriose tastiere di plastica, quindi ora ricevi sequenze di numeri corrispondenti alle lettere che hanno digitato, quindi " l'aquila ha lasciato il nido avvisando gli agenti " diventa
84303245304270533808430637802537808430243687
Ma aspetta! Alcune sequenze T9 sono ambigue ("6263" potrebbe essere "nome", "criniera" o "oboe"; più oscuro, più diventa sospetto!), Quindi cosa fai? Sai che l'unico esame di ammissione che M1S utilizza è riassumere il capolavoro di Marcel Proust "Remembrance of Things Past" in 15 secondi, quindi vuoi scegliere la parola che viene dopo quella precedente in base alla sua distribuzione di frequenza nell'intero chef-d ' œuvre of Proust!
Puoi decifrare il codice e ottenere quello che potrebbe essere il messaggio originale?
Il principio di T9
Il meccanismo di completamento automatico T9 può essere descritto come segue. Associa i caratteri alfabetici ai numeri, come mostrato nella figura sopra.
abc -> 2
def -> 3
ghi -> 4
jkl -> 5
mno -> 6
pqrs -> 7
tuv -> 8
wxyz -> 9
<space> -> 0
<other> -> <is deleted>
Il decodificatore T9 riceve una sequenza di cifre e cerca di indovinare la parola che potrebbe essere digitata con quei tasti premuti. Potrebbe usare una tabella di frequenza standard, ma stiamo facendo un ulteriore passo avanti e prevedendo la parola successiva usando una catena di Markov!
Campione di apprendimento
Il corpus è questa versione pesantemente spogliato di “ricerca del tempo perduto” di Proust ( s/-/ /g
, s/['’]s //g
e s/[^a-zA-Z ]//g
- vattene confondendo possessivo 's
!), Originariamente pubblicato sul sito dell'Università di Adelaide (Il testo di questo lavoro è nel pubblico dominio in Australia).
L'intero testo deve essere analizzato come una stringa, come una lunga frase, come un lungo vettore di parole (qualunque sia più conveniente per la tua lingua), privato delle interruzioni di riga e diviso in parole negli spazi . (Non fornisco un file a paragrafo singolo perché potrebbe essere disapprovato dagli strumenti github.)
Come posso leggere l'intero testo come una stringa / frase? Un esempio in R :
p_raw <- read.table("proust.txt", sep="\t") # Because there are no tabs
p_vec <- as.character(p_raw$V1) # Conversion to character vector
p_str <- paste(p_vec, collapse=" ") # One long string with spaces
p_spl <- strsplit(p_str, split=" ")[[1]] # Vector of 1360883 words
proust <- p_spl[p_spl!=""] # Remove empty entries — 1360797
Compito
Data una sequenza di cifre come un numero, restituisce una possibile stringa di testo che potrebbe essere digitata utilizzando i corrispondenti tasti T9 utilizzando una catena di probabilità per prevedere la parola X successiva in base a questo testo di addestramento trattato come una frase lunga.
Se X è la prima parola T9 del testo e ci sono più ipotesi, scegline una a caso, altrimenti scegli l'unica possibile.
Per tutte le successive parole T9 X (i) precedute da una parola già decifrata w (i-1) :
- Se una parola T9 X può essere convertita in una parola normale x in un modo unico, fallo.
- Se sono disponibili più opzioni di conversione per X , ad esempio x1, x2, ... , cercare la parola indovinata precedente w .
- Se w non è mai seguito da qualcosa che si associa a X nell'opera originale di Proust, scegli uno qualsiasi dei possibili x1, x2, ... a caso.
- Se w X corrisponde sempre a w x1 nell'originale e non ci sono xi simultanei che potrebbero essere mappati in X , scegli x1 .
- Se w X può essere convertito in w x1 , w x2 , ... che può essere trovato nel corpus, allora conta tutti i possibili xi che seguono w e mappano a X nel corpus e scegli xi con probabilità xi / (x1 + x2 + ...) .
Esempio 2a. Se il messaggio è 76630489
, dove 489
potrebbe essere guy
o ivy
(si verificano nel corpus almeno una volta), 7663
può essere decifrato come some
(una prima parola molto probabile). Se some
non è mai seguito da qualcosa che è mappato 489
nel corpus, allora scegli guy
o ivy
a caso con probabilità 0,5.
Esempio 2b. Se il messaggio è 766302277437
, dove 2277437
potrebbe essere barrier
o carrier
, 7663
può essere decifrato come some
. Se Proust è sempre stato utilizzato some carrier
e mai some barrier
, quindi selezionare some carrier
.
Esempio 2c. Supponiamo di voler decifrare la sequenza 536307663
. 5363
era previsto come lend
. 7663
potrebbe essere uno di questi: pond
, roof
e some
. Conta le occorrenze della parola che segue lend
nel corpus di esempio. Supponiamo di ottenere qualcosa del genere (solo per illustrare):
T9 Word following lend Occurrences
7663 some 7
7663 pond 2
7663 roof 1
Quindi, se 7663
è preceduto da lend
, c'è una 7/(7+2+1)=70%
probabilità che 7663
rappresenta some
, 20% pond
e 10% roof
. L'algoritmo dovrebbe produrre lend some
nel 70% dei casi, lend pond
nel 20% dei casi ecc.
Puoi tranquillamente presumere che gli agenti utilizzino solo lettere e spazi az (nessun segno di punteggiatura, nessun carattere possessivo 's
e nessun numero).
Si può anche presumere che gli agenti di M1S non usino mai parole al di fuori dell'ambito di “Remembrance of Things Past” (che è un enorme vocabolario di 29.237 parole!).
La funzionalità T9 è stata implementata in questa sfida , quindi potresti dargli un'occhiata.
Se hai bisogno di aiuto, le catene probabilistiche sono state gloriosamente domate in questa , quella e le seguenti sfide, ma non hai nemmeno bisogno di conoscere il principio di tali catene: tutto è dichiarato nel compito.
Casi test
--Inputs--
20784250276960369
20784250276960369
84303245304270533808430637802537808430243687
94280343084306289072908608430262780482737
94280343084306289072908608430262780482737
--Possible outputs--
c quick brown fox
a stick crown fox
the eagle gas left the nest blest vie agents
what did the navy pay to the coast guards
what did the navy raz un the coast guards
Regole:
- Si applicano scappatoie standard .
- Non conosci il messaggio originale, tutto ciò che ottieni è una sequenza di cifre e il file proust.txt che devi solo caricare nella memoria / spazio di lavoro / qualunque cosa. Non è necessario avere nulla di indipendente; assumere
proust.txt
è sempre accessibile. - L'algoritmo deve essere in grado di produrre output diversi con le rispettive probabilità se è probabile più di un'opzione di decrittografia in base al corpus (vedere Esempio 2c).
Devi rimanere il più discreto possibile, quindi vince il codice più corto!
PS L'ovvio vantaggio di questo algoritmo probabilistico è il fatto che la probabilità che otterrai una vera stringa originale per una stringa decifrata ambigua tende a una - aspetta solo ...
PPS Vedi anche Pronostico per corrispondenza parziale .