Skip to content

Instantly share code, notes, and snippets.

@AleksandrHovhannisyan
Created May 14, 2022 21:55
Show Gist options
  • Save AleksandrHovhannisyan/f23b89beada7884ea38c9cf37d74849a to your computer and use it in GitHub Desktop.
Save AleksandrHovhannisyan/f23b89beada7884ea38c9cf37d74849a to your computer and use it in GitHub Desktop.
Frequency analysis of the ciphertext in Edgar Allen Poe's "The Gold Bug" short story
// https://poestories.com/read/goldbug
const cipherText = `53‡‡†305))6*;4826)4‡.)4‡);806*;48†8¶60))85;1‡(;:‡*8†83(88)5*†;46(;88*96*?;8)*‡(;485);5*†2:*‡(;4956*2(5*-4)8¶8*;4069285);)6†8)4‡‡;1(‡9;48081;8:8‡1;48†85;4)485†528806*81(‡9;48;(88;4(‡?34;48)4‡;161;:188;‡?;`;
const getFrequencyTable = (list) => {
return list.reduce((table, element) => {
if (!table[element]) {
table[element] = {
count: 0,
percentage: 0,
};
}
table[element].count++;
const percentage = Number(
((table[element].count / list.length) * 100).toFixed(2)
);
table[element].percentage = percentage;
return table;
}, {});
};
const cipherLetters = cipherText.split("");
// Sort in descending order by letter count to get the most popular letters first
letterFrequencies = Object.entries(getFrequencyTable(cipherLetters)).sort(
(entry1, entry2) => {
const count1 = entry1[1].count;
const count2 = entry2[1].count;
return count2 - count1;
}
);
/*
[
[ '8', { count: 33, percentage: 16.26 } ],
[ ';', { count: 26, percentage: 12.81 } ],
[ '4', { count: 19, percentage: 9.36 } ],
[ '‡', { count: 16, percentage: 7.88 } ],
[ ')', { count: 16, percentage: 7.88 } ],
[ '*', { count: 13, percentage: 6.4 } ],
[ '5', { count: 12, percentage: 5.91 } ],
[ '6', { count: 11, percentage: 5.42 } ],
[ '(', { count: 10, percentage: 4.93 } ],
[ '1', { count: 8, percentage: 3.94 } ],
[ '†', { count: 8, percentage: 3.94 } ],
[ '0', { count: 6, percentage: 2.96 } ],
[ '2', { count: 5, percentage: 2.46 } ],
[ '9', { count: 5, percentage: 2.46 } ],
[ '3', { count: 4, percentage: 1.97 } ],
[ ':', { count: 4, percentage: 1.97 } ],
[ '?', { count: 3, percentage: 1.48 } ],
[ '¶', { count: 2, percentage: 0.99 } ],
[ '.', { count: 1, percentage: 0.49 } ],
[ '-', { count: 1, percentage: 0.49 } ]
]
*/
console.log(letterFrequencies);
const decipheredMessage = cipherText
// 8 is the most frequently occurring letter, so likely e
.replace(/8/g, "e")
// ;48 appears often, suggesting it is "the"
.replace(/;/g, "t")
.replace(/4/g, "h")
// with the above transformations, we have:
// 53‡‡†305))6*the26)h‡.)h‡)te06*the†e¶60))e5t1‡(t:‡*e†e3(ee)5*†th6(tee*96*?te)*‡(the5)t5*†2:*‡(th956*2(5*-h)e¶e*th0692e5)t)6†e)h‡‡t1(‡9the0e1te:e‡1the†e5th)he5†52ee06*e1(‡9thet(eeth(‡?3hthe)h‡t161t:1eet‡?t
// ‡ appears twice in a row and also after h, suggesting it's o
.replace(/‡/g, "o")
// thet(eeth => the tree th...
.replace(/\(/g, "r")
// 9thetreethro?3hthe => ? = u and 3 = g
.replace(/\?/g, "u")
.replace(/3/g, "g")
// 5goo†g05))6*the26)ho.)ho)te06*the†e¶60))e5t1ort:o*e†egree)5*†th6rtee*96*ute)*orthe5)t5*†2:*orth956*2r5*-h)e¶e*th0692e5)t)6†e)hoot1ro9the0e1te:eo1the†e5th)he5†52ee06*e1ro9thetreethroughthe)hot161t:1eetout
// Since ) appears twice in a row multiple times, safe to assume it's 's' since we already found O and E, the two other letters that frequently repeat themselves.
.replace(/\)/g, "s")
// *orth = north or forth, north seems likely given it's a map
.replace(/\*/g, "n")
// th6rteen => 6 = i
.replace(/6/g, "i")
// thirteen9inutesnorthe => 9 = m
.replace(/9/g, "m")
// se¶enth => ¶ = v
.replace(/¶/g, "v")
// one†egree => † = d
.replace(/†/g, "d")
// inthedevi0ss => 0 = l
.replace(/0/g, "l")
// onedegrees5ndthirteenminutesnorthe => 5 = a
.replace(/5/g, "a")
// 1rom => 1 = f
.replace(/1/g, "f")
// atfort:onedegrees => : = y
.replace(/\:/g, "y")
// and2ynorth => 2 = b
.replace(/2/g, "b")
// bynorthmainbran-hseventhlimbeast => - = c
.replace(/\-/g, "c")
// agoodglassinthebisho.shostel => . = p
.replace(/\./g, "p");
// a good glass in the bishops hostel in the devils seat forty one degrees
// and thirteen minutes northeast and by north main branch seventh limb
// east side shoot from the left eye of the deaths head a beeline from
// the tree through the shot fifty feet out
console.log(decipheredMessage);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment