xxxxxxxxxx
<!-- Cryptogram Interactive Puzzle
Solve the puzzle by replacing letters to reveal the hidden message.
Use the keyboard and mouse to move the cursor.
Type a letter to make a guess and advance the cursor.
Correct mistakes by typing over them or with backspace and delete.
-->
<style>
.puzzle { font-family: monospace; font-size: 2em }
.guess { font-style: normal; font-weight: bold; color: darkslateblue}
.solved { color: darkgreen}
.error { color: red }
.cursor { background-color: lightgray }
.curchr { text-decoration: underline }
</style>
<body>
<h1>Cryptogram</h1>
<p>Solve the puzzle by replacing letters to reveal the hidden message.</p>
<p>Use the keyboard and mouse to move the cursor.
Type a letter to enter a guess and advance the cursor.
Correct mistakes by typing over them or with backspace and delete.</p>
<p id="puzzle"></p>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var encodeCypher = {};
var decodeCypher = {};
var textClear = "";
var textAlpha = "";
var textKey = "";
var textHidden = "";
var textSolved = "";
function setPuzzle(text) {
textClear = text;
textAlpha = makeAlpha(textClear);
textKey = makeKey(textAlpha.length);
encodeCypher = makeCypher(textAlpha, textKey);
decodeCypher = makeCypher(textKey, textKey.toLowerCase());
textHidden = translate(textClear, encodeCypher, true);
textSolved = translate(textHidden, decodeCypher, true);
}
function setGuess(cypherVal, clearVal) {
cypherVal = cypherVal.toUpperCase();
clearVal = clearVal.toUpperCase();
if(decodeCypher.hasOwnProperty(cypherVal)) {
decodeCypher[cypherVal] = clearVal;
textSolved = translate(textHidden, decodeCypher, true);
}
}
function clearGuess(cypherVal) {
cypherVal = cypherVal.toUpperCase();
if(decodeCypher.hasOwnProperty(cypherVal)) {
decodeCypher[cypherVal] = cypherVal.toLowerCase();
textSolved = translate(textHidden, decodeCypher, true);
}
}
function makeCypher(from, to) {
var cypher = {};
for(var i = 0; i < from.length; ++i) {
cypher[from.charAt(i)] = to.charAt(i);
}
return cypher;
}
function translate(text, cypher, preserve) {
var arry = text.split("");
for(var i = 0; i < arry.length; ++i) {
var arryval = arry[i].toUpperCase();
if(cypher.hasOwnProperty(arryval)) {
var cypherval = cypher[arryval];
if(!preserve) {
arry[i] = cypherval;
} else {
if(arryval != arry[i]) {
arry[i] = cypherval.toLowerCase();
} else {
arry[i] = cypherval.toUpperCase();
}
}
}
}
return arry.join("");
}
function makeAlpha(text) {
var arry = text.toUpperCase().replace(/[^A-Z]/g,"").split("");
arry.sort();
var i = 0, j = 0;
while(j < arry.length) {
arry[i] = arry[j];
while(j < arry.length && arry[i] === arry[j]) {
++j;
}
++i;
}
return arry.slice(0, i).join("");
}
function scramble(alpha) {
var arry = alpha.split("");
for(var i = arry.length; 0 < i; --i) {
var j = Math.floor(i * Math.random());
var tmp = arry[i-1];
arry[i-1] = arry[j];
arry[j] = tmp;
}
return arry.join("");
}
function makeKey(length) {
return scramble(alphabet).substr(0, length);
}
</script>
<script>
var puzzleOptions = [
"By three methods we may learn wisdom: first, by reflection, which is noblest; second, by imitation, which is easiest; and third, by experience, which is the bitterest. --Confucius",
"Computers make it easier to do a lot of things, but most of the things they make it easier to do don't need to be done. --Andy Rooney",
"The typewriting machine, when played with expression, is no more annoying than the piano when played by a sister or near relation. --Oscar Wilde.",
"The first rule of any technology used in a business is that automation applied to an efficient operation will magnify the efficiency. The second is that automation applied to an inefficient operation will magnify the inefficiency. --Bill Gates",
];
setPuzzle(puzzleOptions[Math.floor(Math.random()*puzzleOptions.length)]);
var cursorPos = 0;
var cursorBlink = true;
var cursorTimer = null;
var puzzle = d3.selectAll("#puzzle");
puzzle.classed("puzzle", true);
var data = puzzle.selectAll("*").data(d3.range(textSolved.length));
data.enter().append("span");
data.exit().remove();
data.order();
function getTextAt(i) {
return textSolved.charAt(i);
}
function getGuessAt(i) {
var hiddenVal = textHidden.charAt(i).toUpperCase();
if(!decodeCypher.hasOwnProperty(hiddenVal)) {
return false;
} else {
var decodeVal = decodeCypher[hiddenVal];
return decodeVal === decodeVal.toUpperCase();
}
}
function update() {
var curChr = textHidden.charAt(cursorPos).toUpperCase();
if (curChr === curChr.toLowerCase())
curChr = undefined;
var guessCount = {};
for(var k in decodeCypher) {
var decodeVal = decodeCypher[k];
if(decodeVal === decodeVal.toUpperCase()) {
guessCount[decodeVal] = 1 + (guessCount[decodeVal] || 0);
}
}
function getErrorAt(i) {
if(!getGuessAt(i)) {
return false;
} else {
var decodeVal = textSolved.charAt(i).toUpperCase();
return guessCount[decodeVal] > 1;
}
}
var elems = puzzle.selectAll("*");
elems.text(getTextAt);
elems.classed("guess", getGuessAt);
elems.classed("error", getErrorAt);
elems.classed("curchr", function(i) {
return curChr === textHidden.charAt(i).toUpperCase();
});
elems.classed("solved", textSolved === textClear);
elems.on("click", cursorUpdate);
}
function cursorCallback() {
var data = puzzle.selectAll("*");
data.classed("cursor", function(d) {
return d === cursorPos ? cursorBlink : false; });
cursorBlink = !cursorBlink;
}
function cursorUpdate(pos) {
if(cursorTimer != null) {
clearInterval(cursorTimer);
}
while(pos < 0) {
pos += textHidden.length;
}
while(textHidden.length <= pos) {
pos -= textHidden.length;
}
cursorPos = pos;
cursorBlink = true;
update();
cursorCallback();
cursorTimer = setInterval(cursorCallback, 800);
}
function setGuessAtCursor(val) {
setGuess(textHidden.charAt(cursorPos), val);
update();
}
function clearGuessAtCursor() {
clearGuess(textHidden.charAt(cursorPos));
update();
}
function updateKey(key) {
switch(key) {
case 37: //left arrow
cursorUpdate(cursorPos-1);
return true;
case 32: //space
case 39: //right arrow
cursorUpdate(cursorPos+1);
return true;
case 36: //home
cursorUpdate(0);
return true;
case 35: //end
cursorUpdate(-1);
return true;
case 8: //backspace
cursorUpdate(cursorPos-1);
clearGuessAtCursor();
return true;
case 46: //delete
clearGuessAtCursor();
return true;
}
// letter
if(65 <= key && key < 91) {
var val = String.fromCharCode(key).toUpperCase();
setGuessAtCursor(val.toUpperCase());
cursorUpdate(cursorPos+1);
return true;
}
return false
}
function keyDownCallback() {
if(updateKey(d3.event.keyCode || d3.event.which))
d3.event.preventDefault();
}
d3.selectAll("body").on("keydown", keyDownCallback);
cursorUpdate(0);
</script>
</body>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js